summaryrefslogtreecommitdiffstats
path: root/web/react/components
diff options
context:
space:
mode:
Diffstat (limited to 'web/react/components')
-rw-r--r--web/react/components/channel_header.jsx7
-rw-r--r--web/react/components/channel_notifications.jsx10
-rw-r--r--web/react/components/get_link_modal.jsx2
-rw-r--r--web/react/components/mention_list.jsx9
-rw-r--r--web/react/components/more_direct_channels.jsx2
-rw-r--r--web/react/components/msg_typing.jsx8
-rw-r--r--web/react/components/post.jsx18
-rw-r--r--web/react/components/post_list.jsx111
-rw-r--r--web/react/components/post_right.jsx20
-rw-r--r--web/react/components/search_results.jsx8
-rw-r--r--web/react/components/sidebar.jsx11
-rw-r--r--web/react/components/team_settings.jsx7
-rw-r--r--web/react/components/textbox.jsx4
-rw-r--r--web/react/components/user_settings.jsx19
-rw-r--r--web/react/components/view_image.jsx2
15 files changed, 148 insertions, 90 deletions
diff --git a/web/react/components/channel_header.jsx b/web/react/components/channel_header.jsx
index 48cb4d13b..68de80228 100644
--- a/web/react/components/channel_header.jsx
+++ b/web/react/components/channel_header.jsx
@@ -4,6 +4,7 @@
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 UserProfile = require( './user_profile.jsx' );
var NavbarSearchBox =require('./search_bar.jsx');
var AsyncClient = require('../utils/async_client.jsx');
@@ -82,6 +83,7 @@ module.exports = React.createClass({
ChannelStore.addExtraInfoChangeListener(this._onChange);
PostStore.addSearchChangeListener(this._onChange);
UserStore.addChangeListener(this._onChange);
+ SocketStore.addChangeListener(this._onSocketChange);
},
componentWillUnmount: function() {
ChannelStore.removeChangeListener(this._onChange);
@@ -96,6 +98,11 @@ module.exports = React.createClass({
}
$(".channel-header__info .description").popover({placement : 'bottom', trigger: 'hover', html: true, delay: {show: 500, hide: 500}});
},
+ _onSocketChange: function(msg) {
+ if(msg.action === "new_user") {
+ AsyncClient.getChannelExtraInfo(true);
+ }
+ },
getInitialState: function() {
return getStateFromStores();
},
diff --git a/web/react/components/channel_notifications.jsx b/web/react/components/channel_notifications.jsx
index fa9ab42ae..38bc91682 100644
--- a/web/react/components/channel_notifications.jsx
+++ b/web/react/components/channel_notifications.jsx
@@ -16,12 +16,12 @@ module.exports = React.createClass({
var self = this;
$(this.refs.modal.getDOMNode()).on('show.bs.modal', function(e) {
var button = e.relatedTarget;
- var channel_id = button.dataset.channelid;
+ var channel_id = button.getAttribute('data-channelid');
var notifyLevel = ChannelStore.getMember(channel_id).notify_level;
var quietMode = false;
if (notifyLevel === "quiet") quietMode = true;
- self.setState({ notify_level: notifyLevel, quiet_mode: quietMode, title: button.dataset.title, channel_id: channel_id });
+ self.setState({ notify_level: notifyLevel, quiet_mode: quietMode, title: button.getAttribute('data-title'), channel_id: channel_id });
});
},
componentWillUnmount: function() {
@@ -97,7 +97,7 @@ module.exports = React.createClass({
var inputs = [];
inputs.push(
- <div className="col-sm-12">
+ <div>
<div className="radio">
<label>
<input type="radio" checked={notifyActive[0]} onClick={function(){self.handleRadioClick("all")}}>For all activity</input>
@@ -158,7 +158,7 @@ module.exports = React.createClass({
var inputs = [];
inputs.push(
- <div className="col-sm-12">
+ <div>
<div className="btn-group" data-toggle="buttons-radio">
<button className={"btn btn-default "+quietActive[0]} onClick={function(){self.handleQuietToggle(true)}}>On</button>
<button className={"btn btn-default "+quietActive[1]} onClick={function(){self.handleQuietToggle(false)}}>Off</button>
@@ -167,7 +167,7 @@ module.exports = React.createClass({
);
inputs.push(
- <div className="col-sm-12">
+ <div>
<br/>
Enabling quiet mode will turn off desktop notifications and only mark the channel as unread if you have been mentioned.
</div>
diff --git a/web/react/components/get_link_modal.jsx b/web/react/components/get_link_modal.jsx
index 334591ee3..69e565185 100644
--- a/web/react/components/get_link_modal.jsx
+++ b/web/react/components/get_link_modal.jsx
@@ -42,7 +42,7 @@ module.exports = React.createClass({
</div>
<div className="modal-footer">
<button type="button" className="btn btn-default" data-dismiss="modal">Close</button>
- <button data-copy-btn type="button" className="btn btn-primary" data-clipboard-text={this.state.value}>Copy Link</button>
+ <button data-copy-btn type="button" className="btn btn-primary pull-left" data-clipboard-text={this.state.value}>Copy Link</button>
</div>
</div>
</div>
diff --git a/web/react/components/mention_list.jsx b/web/react/components/mention_list.jsx
index eb21e0efe..b666fcfae 100644
--- a/web/react/components/mention_list.jsx
+++ b/web/react/components/mention_list.jsx
@@ -14,7 +14,7 @@ module.exports = React.createClass({
PostStore.addMentionDataChangeListener(this._onChange);
var self = this;
- $('#'+this.props.id).on('keypress.mentionlist',
+ $('body').on('keypress.mentionlist', '#'+this.props.id,
function(e) {
if (!self.isEmpty() && self.state.mentionText != '-1' && e.which === 13) {
e.stopPropagation();
@@ -23,10 +23,15 @@ module.exports = React.createClass({
}
}
);
+ $(document).click(function() {
+ if($('#'+self.props.id).length && $('#'+self.props.id).get(0) !== $(':focus').get(0)) {
+ self.setState({mentionText: "-1"})
+ }
+ });
},
componentWillUnmount: function() {
PostStore.removeMentionDataChangeListener(this._onChange);
- $('#'+this.props.id).off('keypress.mentionlist');
+ $('body').off('keypress.mentionlist', '#'+this.props.id);
},
_onChange: function(id, mentionText, excludeList) {
if (id !== this.props.id) return;
diff --git a/web/react/components/more_direct_channels.jsx b/web/react/components/more_direct_channels.jsx
index 2785dc8e0..182d8884d 100644
--- a/web/react/components/more_direct_channels.jsx
+++ b/web/react/components/more_direct_channels.jsx
@@ -49,7 +49,7 @@ module.exports = React.createClass({
<span aria-hidden="true">&times;</span>
<span className="sr-only">Close</span>
</button>
- <h4 className="modal-title">More Direct Messages</h4>
+ <h4 className="modal-title">More Private Messages</h4>
</div>
<div className="modal-body">
<ul className="nav nav-pills nav-stacked">
diff --git a/web/react/components/msg_typing.jsx b/web/react/components/msg_typing.jsx
index 9d3904757..a6953028f 100644
--- a/web/react/components/msg_typing.jsx
+++ b/web/react/components/msg_typing.jsx
@@ -11,6 +11,11 @@ module.exports = React.createClass({
componentDidMount: function() {
SocketStore.addChangeListener(this._onChange);
},
+ componentWillReceiveProps: function(newProps) {
+ if(this.props.channelId !== newProps.channelId) {
+ this.setState({text:""});
+ }
+ },
componentWillUnmount: function() {
SocketStore.removeChangeListener(this._onChange);
},
@@ -37,6 +42,9 @@ module.exports = React.createClass({
}, 3000);
}
}
+ else if (msg.action == "posted" && msg.channel_id === this.props.channelId) {
+ this.setState({text:""})
+ }
},
getInitialState: function() {
return { text: "" };
diff --git a/web/react/components/post.jsx b/web/react/components/post.jsx
index afe978495..04b5ba082 100644
--- a/web/react/components/post.jsx
+++ b/web/react/components/post.jsx
@@ -6,13 +6,14 @@ var PostBody = require('./post_body.jsx');
var PostInfo = require('./post_info.jsx');
var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
var Constants = require('../utils/constants.jsx');
+var UserStore = require('../stores/user_store.jsx');
var ActionTypes = Constants.ActionTypes;
module.exports = React.createClass({
componentDidMount: function() {
- $('.edit-modal').on('show.bs.modal', function () {
- $('.edit-modal .edit-modal-body').css('overflow-y', 'auto');
- $('.edit-modal .edit-modal-body').css('max-height', $(window).height() * 0.7);
+ $('.modal').on('show.bs.modal', function () {
+ $('.modal-body').css('overflow-y', 'auto');
+ $('.modal-body').css('max-height', $(window).height() * 0.7);
});
},
handleCommentClick: function(e) {
@@ -56,7 +57,7 @@ module.exports = React.createClass({
var error = this.state.error ? <div className='form-group has-error'><label className='control-label'>{ this.state.error }</label></div> : null;
- if(this.props.sameRoot){
+ if (this.props.sameRoot){
rootUser = "same--root";
}
else {
@@ -64,13 +65,18 @@ module.exports = React.createClass({
}
var postType = "";
- if(type != "Post"){
+ if (type != "Post"){
postType = "post--comment";
}
+ var currentUserCss = "";
+ if (UserStore.getCurrentId() === post.user_id) {
+ currentUserCss = "current--user";
+ }
+
return (
<div>
- <div id={post.id} className={"post " + this.props.sameUser + " " + rootUser + " " + postType}>
+ <div id={post.id} className={"post " + this.props.sameUser + " " + rootUser + " " + postType + " " + currentUserCss}>
{ !this.props.hideProfilePic ?
<div className="post-profile-img__container">
<img className="post-profile-img" src={"/api/v1/users/" + post.user_id + "/image"} height="36" width="36" />
diff --git a/web/react/components/post_list.jsx b/web/react/components/post_list.jsx
index e37de8d88..fc5157ce6 100644
--- a/web/react/components/post_list.jsx
+++ b/web/react/components/post_list.jsx
@@ -123,7 +123,7 @@ module.exports = React.createClass({
$('.post-list__content div .post').removeClass('post--last');
$('.post-list__content div:last-child .post').addClass('post--last');
- $('body').on('mouseenter mouseleave', '.post', function(ev){
+ $('body').on('mouseenter mouseleave', '.post:not(.post--comment.same--root)', function(ev){
if(ev.type === 'mouseenter'){
$(this).parent('div').prev('.date-separator, .new-separator').addClass('hovered--after');
$(this).parent('div').next('.date-separator, .new-separator').addClass('hovered--before');
@@ -295,7 +295,7 @@ module.exports = React.createClass({
},
render: function() {
var order = [];
- var posts = {};
+ var posts;
var last_viewed = Number.MAX_VALUE;
@@ -324,13 +324,7 @@ module.exports = React.createClass({
if (order.length > 0 && order.length % Constants.POST_CHUNK_SIZE === 0) {
more_messages = <a ref="loadmore" className="more-messages-text theme" href="#" onClick={this.getMorePosts}>Load more messages</a>;
} else if (channel.type === 'D') {
- var userIds = channel.name.split('__');
- var teammate;
- if (userIds.length === 2 && userIds[0] === user_id) {
- teammate = UserStore.getProfile(userIds[1]);
- } else if (userIds.length === 2 && userIds[1] === user_id) {
- teammate = UserStore.getProfile(userIds[0]);
- }
+ var teammate = utils.getDirectTeammate(channel.id)
if (teammate) {
var teammate_name = teammate.full_name.length > 0 ? teammate.full_name : teammate.username;
@@ -342,13 +336,13 @@ module.exports = React.createClass({
<div className="channel-intro-profile">
<strong><UserProfile userId={teammate.id} /></strong>
</div>
- <p className="channel-intro-text">{"This is the start of your direct message history with " + teammate_name + "." }<br/>{"Direct messages and files shared here are not shown to people outside this area."}</p>
+ <p className="channel-intro-text">{"This is the start of your private message history with " + teammate_name + "." }<br/>{"Private messages and files shared here are not shown to people outside this area."}</p>
</div>
);
} else {
more_messages = (
<div className="channel-intro">
- <p className="channel-intro-text">{"This is the start of your direct message history with this " + strings.Team + "mate. Direct messages and files shared here are not shown to people outside this area."}</p>
+ <p className="channel-intro-text">{"This is the start of your private message history with this " + strings.Team + "mate. Private messages and files shared here are not shown to people outside this area."}</p>
</div>
);
}
@@ -414,55 +408,70 @@ module.exports = React.createClass({
}
var postCtls = [];
- var previousPostDay = posts[order[order.length-1]] ? utils.getDateForUnixTicks(posts[order[order.length-1]].create_at): new Date();
- var currentPostDay = new Date();
- for (var i = order.length-1; i >= 0; i--) {
- var post = posts[order[i]];
- var parentPost;
+ if (posts != undefined) {
+ var previousPostDay = posts[order[order.length-1]] ? utils.getDateForUnixTicks(posts[order[order.length-1]].create_at): new Date();
+ var currentPostDay = new Date();
- if (post.parent_id) {
- parentPost = posts[post.parent_id];
- } else {
- parentPost = null;
- }
+ for (var i = order.length-1; i >= 0; i--) {
+ var post = posts[order[i]];
+ var parentPost;
- var sameUser = i < order.length-1 && posts[order[i+1]].user_id === post.user_id && post.create_at - posts[order[i+1]].create_at <= 1000*60*5 ? "same--user" : "";
- var sameRoot = i < order.length-1 && post.root_id != "" && (posts[order[i+1]].id === post.root_id || posts[order[i+1]].root_id === post.root_id) ? true : false;
+ if (post.parent_id) {
+ parentPost = posts[post.parent_id];
+ } else {
+ parentPost = null;
+ }
- // we only hide the profile pic if the previous post is not a comment, the current post is not a comment, and the previous post was made by the same user as the current post
- var hideProfilePic = i < order.length-1 && posts[order[i+1]].user_id === post.user_id && posts[order[i+1]].root_id === '' && post.root_id === '';
+ var sameUser = i < order.length-1 && posts[order[i+1]].user_id === post.user_id && post.create_at - posts[order[i+1]].create_at <= 1000*60*5 ? "same--user" : "";
+ var sameRoot = i < order.length-1 && post.root_id != "" && (posts[order[i+1]].id === post.root_id || posts[order[i+1]].root_id === post.root_id) ? true : false;
- // check if it's the last comment in a consecutive string of comments on the same post
- var isLastComment = false;
- if (utils.isComment(post)) {
- // it is the last comment if it is last post in the channel or the next post has a different root post
- isLastComment = (i === 0 || posts[order[i-1]].root_id != post.root_id);
- }
+ // we only hide the profile pic if the previous post is not a comment, the current post is not a comment, and the previous post was made by the same user as the current post
+ var hideProfilePic = i < order.length-1 && posts[order[i+1]].user_id === post.user_id && posts[order[i+1]].root_id === '' && post.root_id === '';
- var postCtl = <Post sameUser={sameUser} sameRoot={sameRoot} post={post} parentPost={parentPost} key={post.id} posts={posts} hideProfilePic={hideProfilePic} isLastComment={isLastComment} />;
+ // check if it's the last comment in a consecutive string of comments on the same post
+ var isLastComment = false;
+ if (utils.isComment(post)) {
+ // it is the last comment if it is last post in the channel or the next post has a different root post
+ isLastComment = (i === 0 || posts[order[i-1]].root_id != post.root_id);
+ }
- currentPostDay = utils.getDateForUnixTicks(post.create_at);
- if(currentPostDay.getDate() !== previousPostDay.getDate() || currentPostDay.getMonth() !== previousPostDay.getMonth() || currentPostDay.getFullYear() !== previousPostDay.getFullYear()) {
- postCtls.push(
- <div className="date-separator">
- <hr className="separator__hr" />
- <div className="separator__text">{currentPostDay.toDateString()}</div>
- </div>
- );
- }
+ var postCtl = <Post sameUser={sameUser} sameRoot={sameRoot} post={post} parentPost={parentPost} key={post.id} posts={posts} hideProfilePic={hideProfilePic} isLastComment={isLastComment} />;
- if (post.create_at > last_viewed && !rendered_last_viewed) {
- rendered_last_viewed = true;
- postCtls.push(
- <div className="new-separator">
- <hr id="new_message" className="separator__hr" />
- <div className="separator__text">New Messages</div>
- </div>
- );
+ currentPostDay = utils.getDateForUnixTicks(post.create_at);
+ if(currentPostDay.getDate() !== previousPostDay.getDate() || currentPostDay.getMonth() !== previousPostDay.getMonth() || currentPostDay.getFullYear() !== previousPostDay.getFullYear()) {
+ postCtls.push(
+ <div className="date-separator">
+ <hr className="separator__hr" />
+ <div className="separator__text">{currentPostDay.toDateString()}</div>
+ </div>
+ );
+ }
+
+ if (post.create_at > last_viewed && !rendered_last_viewed) {
+ rendered_last_viewed = true;
+ postCtls.push(
+ <div className="new-separator">
+ <hr id="new_message" className="separator__hr" />
+ <div className="separator__text">New Messages</div>
+ </div>
+ );
+ }
+ postCtls.push(postCtl);
+ previousPostDay = utils.getDateForUnixTicks(post.create_at);
}
- postCtls.push(postCtl);
- previousPostDay = utils.getDateForUnixTicks(post.create_at);
+ }
+ else {
+ postCtls.push(
+ <div ref="loadingscreen" className="loading-screen">
+ <div className="loading__content">
+ <h3>Loading</h3>
+ <div id="round_1" className="round"></div>
+ <div id="round_2" className="round"></div>
+ <div id="round_3" className="round"></div>
+ </div>
+ </div>
+ );
}
return (
diff --git a/web/react/components/post_right.jsx b/web/react/components/post_right.jsx
index 43be60afa..2c28c5d9f 100644
--- a/web/react/components/post_right.jsx
+++ b/web/react/components/post_right.jsx
@@ -68,9 +68,14 @@ RootPost = React.createClass({
var filenames = this.props.post.filenames;
var isOwner = UserStore.getCurrentId() == this.props.post.user_id;
- var type = "Post"
+ var type = "Post";
if (this.props.post.root_id.length > 0) {
- type = "Comment"
+ type = "Comment";
+ }
+
+ var currentUserCss = "";
+ if (UserStore.getCurrentId() === this.props.post.user_id) {
+ currentUserCss = "current--user";
}
if (filenames) {
@@ -84,7 +89,7 @@ RootPost = React.createClass({
if (fileSplit.length < 2) continue;
var ext = fileSplit[fileSplit.length-1];
- fileSplit.splice(fileSplit.length-1,1)
+ fileSplit.splice(fileSplit.length-1,1);
var filePath = fileSplit.join('.');
var filename = filePath.split('/')[filePath.split('/').length-1];
@@ -111,7 +116,7 @@ RootPost = React.createClass({
}
return (
- <div className="post post--root">
+ <div className={"post post--root " + currentUserCss}>
<div className="post-profile-img__container">
<img className="post-profile-img" src={"/api/v1/users/" + this.props.post.user_id + "/image"} height="36" width="36" />
</div>
@@ -170,6 +175,11 @@ CommentPost = React.createClass({
var commentClass = "post";
+ var currentUserCss = "";
+ if (UserStore.getCurrentId() === this.props.post.user_id) {
+ currentUserCss = "current--user";
+ }
+
var postImageModalId = "rhs_comment_view_image_modal_" + this.props.post.id;
var filenames = this.props.post.filenames;
var isOwner = UserStore.getCurrentId() == this.props.post.user_id;
@@ -219,7 +229,7 @@ CommentPost = React.createClass({
var message = utils.textToJsx(this.props.post.message);
return (
- <div className={commentClass}>
+ <div className={commentClass + " " + currentUserCss}>
<div className="post-profile-img__container">
<img className="post-profile-img" src={"/api/v1/users/" + this.props.post.user_id + "/image"} height="36" width="36" />
</div>
diff --git a/web/react/components/search_results.jsx b/web/react/components/search_results.jsx
index 51aefd3b8..003a38b7e 100644
--- a/web/react/components/search_results.jsx
+++ b/web/react/components/search_results.jsx
@@ -43,6 +43,7 @@ SearchItem = React.createClass({
e.preventDefault();
var self = this;
+
client.getPost(
this.props.post.channel_id,
this.props.post.id,
@@ -64,6 +65,11 @@ SearchItem = React.createClass({
dispatchError(err, "getPost");
}
);
+
+ var postChannel = ChannelStore.get(this.props.post.channel_id);
+ var teammate = postChannel.type === 'D' ? utils.getDirectTeammate(this.props.post.channel_id).username : "";
+
+ utils.switchChannel(postChannel,teammate);
},
render: function() {
@@ -73,7 +79,7 @@ SearchItem = React.createClass({
if (channel) {
if (channel.type === 'D') {
- channelName = "Direct Message";
+ channelName = "Private Message";
} else {
channelName = channel.display_name;
}
diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx
index 10017c7ee..0e4d38fe0 100644
--- a/web/react/components/sidebar.jsx
+++ b/web/react/components/sidebar.jsx
@@ -269,13 +269,8 @@ var SidebarLoggedIn = React.createClass({
var channel = ChannelStore.getCurrent();
if (channel) {
if (channel.type === 'D') {
- userIds = channel.name.split('__');
- if (userIds.length < 2) return;
- if (userIds[0] == UserStore.getCurrentId() && UserStore.getProfile(userIds[1])) {
- document.title = UserStore.getProfile(userIds[1]).username + " " + document.title.substring(document.title.lastIndexOf("-"));
- } else if (userIds[1] == UserStore.getCurrentId() && UserStore.getProfile(userIds[0])) {
- document.title = UserStore.getProfile(userIds[0]).username + " " + document.title.substring(document.title.lastIndexOf("-"));
- }
+ var teammate_username = utils.getDirectTeammate(channel.id).username
+ document.title = teammate_username + " " + document.title.substring(document.title.lastIndexOf("-"));
} else {
document.title = channel.display_name + " " + document.title.substring(document.title.lastIndexOf("-"))
}
@@ -414,7 +409,7 @@ var SidebarLoggedIn = React.createClass({
{privateChannelItems}
</ul>
<ul className="nav nav-pills nav-stacked">
- <li><h4>Direct Messages</h4></li>
+ <li><h4>Private Messages</h4></li>
{directMessageItems}
{ this.state.hideDirectChannels.length > 0 ?
<li><a href="#" data-toggle="modal" className="nav-more" data-target="#more_direct_channels" data-channels={JSON.stringify(this.state.hideDirectChannels)}>{"More ("+this.state.hideDirectChannels.length+")"}</a></li>
diff --git a/web/react/components/team_settings.jsx b/web/react/components/team_settings.jsx
index a43e5d2f0..166b1f38b 100644
--- a/web/react/components/team_settings.jsx
+++ b/web/react/components/team_settings.jsx
@@ -78,13 +78,14 @@ var FeatureTab = React.createClass({
<button className={"btn btn-default "+valetActive[0]} onClick={function(){self.handleValetRadio("true")}}>On</button>
<button className={"btn btn-default "+valetActive[1]} onClick={function(){self.handleValetRadio("false")}}>Off</button>
</div>
- <div><br/>Warning: Turning on the Valet feature and using it with any third party software increases the risk of a security breach.</div>
+ <div><br/>Valet is a preview feature for enabling a non-user account limited to basic member permissions that can be manipulated by 3rd parties.<br/><br/>IMPORTANT: The preview version of Valet should not be used without a secure connection and a trusted 3rd party, since user credentials are used to connect. OAuth2 will be used in the final release.</div>
+ <br></br>
</div>
);
valetSection = (
<SettingItemMax
- title="Valet"
+ title="Valet (Preview - EXPERTS ONLY)"
inputs={inputs}
submit={this.submitValetFeature}
server_error={server_error}
@@ -102,7 +103,7 @@ var FeatureTab = React.createClass({
valetSection = (
<SettingItemMin
- title="Valet"
+ title="Valet (Preview - EXPERTS ONLY)"
describe={describe}
updateSection={function(){self.props.updateSection("valet");}}
/>
diff --git a/web/react/components/textbox.jsx b/web/react/components/textbox.jsx
index 934e863a2..6b746aa78 100644
--- a/web/react/components/textbox.jsx
+++ b/web/react/components/textbox.jsx
@@ -78,6 +78,8 @@ module.exports = React.createClass({
var re = new RegExp('( |^)@' + m + '( |$|\n)', 'm');
html = html.replace(re, '$1<span class="mention">@'+m+'</span>$2');
}
+ var re2 = new RegExp('(^$)(?![.\n])', 'gm');
+ html = html.replace(re2, '<br/><br/>');
$(this.refs.textdiv.getDOMNode()).html(html);
},
handleChange: function() {
@@ -262,6 +264,8 @@ module.exports = React.createClass({
$(d).css({'height':'auto','overflow-y':'scroll'}).height(167);
$(w).css({'height':'auto'}).height(167);
}
+
+ $(d).scrollTop($(e).scrollTop());
},
handleFocus: function() {
var elm = this.refs.message.getDOMNode();
diff --git a/web/react/components/user_settings.jsx b/web/react/components/user_settings.jsx
index f97a06db3..b4c3747af 100644
--- a/web/react/components/user_settings.jsx
+++ b/web/react/components/user_settings.jsx
@@ -179,7 +179,7 @@ var NotificationsTab = React.createClass({
</div>
<div className="radio">
<label>
- <input type="radio" checked={notifyActive[1]} onClick={function(){self.handleNotifyRadio("mention")}}>Only for mentions and direct messages</input>
+ <input type="radio" checked={notifyActive[1]} onClick={function(){self.handleNotifyRadio("mention")}}>Only for mentions and private messages</input>
</label>
<br/>
</div>
@@ -203,7 +203,7 @@ var NotificationsTab = React.createClass({
} else {
var describe = "";
if (this.state.notify_level === "mention") {
- describe = "Only for mentions and direct messages";
+ describe = "Only for mentions and private messages";
} else if (this.state.notify_level === "none") {
describe = "Never";
} else {
@@ -282,7 +282,7 @@ var NotificationsTab = React.createClass({
<button className={"btn btn-default "+emailActive[0]} onClick={function(){self.handleEmailRadio("true")}}>On</button>
<button className={"btn btn-default "+emailActive[1]} onClick={function(){self.handleEmailRadio("false")}}>Off</button>
</div>
- <div><br/>{"Email notifications are sent for mentions and direct messages after you have been away from " + config.SiteName + " for 5 minutes."}</div>
+ <div><br/>{"Email notifications are sent for mentions and private messages after you have been away from " + config.SiteName + " for 5 minutes."}</div>
</div>
);
@@ -809,6 +809,11 @@ var GeneralTab = React.createClass({
if(!this.submitActive) return;
+ if(this.state.picture.type !== "image/jpeg") {
+ this.setState({client_error: "Only JPG images may be used for profile pictures"});
+ return;
+ }
+
formData = new FormData();
formData.append('image', this.state.picture, this.state.picture.name);
@@ -839,11 +844,13 @@ var GeneralTab = React.createClass({
updatePicture: function(e) {
if (e.target.files && e.target.files[0]) {
this.setState({ picture: e.target.files[0] });
+
+ this.submitActive = true;
+ this.setState({client_error:null})
+
} else {
this.setState({ picture: null });
}
-
- this.submitActive = true
},
updateSection: function(section) {
this.setState({client_error:""})
@@ -984,7 +991,7 @@ var GeneralTab = React.createClass({
submit={this.submitPicture}
src={"/api/v1/users/" + user.id + "/image"}
server_error={server_error}
- client_error={email_error}
+ client_error={client_error}
updateSection={function(e){self.updateSection("");e.preventDefault();}}
picture={this.state.picture}
pictureChange={this.updatePicture}
diff --git a/web/react/components/view_image.jsx b/web/react/components/view_image.jsx
index c573e9dbb..38f439946 100644
--- a/web/react/components/view_image.jsx
+++ b/web/react/components/view_image.jsx
@@ -161,7 +161,7 @@ module.exports = React.createClass({
<div className="image-links">
{ config.AllowPublicLink ?
<div>
- <a href="#" className="text" data-title="Public Image" onClick={this.getPublicLink}>Get Public Link</a>
+ <a href="#" className="public-link text" data-title="Public Image" onClick={this.getPublicLink}>Get Public Link</a>
<span className="text"> | </span>
</div>
: "" }