summaryrefslogtreecommitdiffstats
path: root/web/react/components
diff options
context:
space:
mode:
Diffstat (limited to 'web/react/components')
-rw-r--r--web/react/components/access_history_modal.jsx2
-rw-r--r--web/react/components/activity_log_modal.jsx2
-rw-r--r--web/react/components/center_panel.jsx3
-rw-r--r--web/react/components/channel_header.jsx14
-rw-r--r--web/react/components/channel_invite_modal.jsx38
-rw-r--r--web/react/components/channel_members_modal.jsx17
-rw-r--r--web/react/components/invite_member_modal.jsx2
-rw-r--r--web/react/components/member_list_item.jsx4
-rw-r--r--web/react/components/more_direct_channels.jsx2
-rw-r--r--web/react/components/navbar.jsx14
-rw-r--r--web/react/components/post_attachment_oembed.jsx35
-rw-r--r--web/react/components/post_body.jsx21
-rw-r--r--web/react/components/post_body_additional_content.jsx6
-rw-r--r--web/react/components/post_info.jsx81
-rw-r--r--web/react/components/posts_view_container.jsx9
-rw-r--r--web/react/components/providers.json158
-rw-r--r--web/react/components/rhs_thread.jsx9
-rw-r--r--web/react/components/search_results_item.jsx2
-rw-r--r--web/react/components/suggestion/search_suggestion_list.jsx2
-rw-r--r--web/react/components/suggestion/suggestion_box.jsx34
-rw-r--r--web/react/components/suggestion/suggestion_list.jsx5
-rw-r--r--web/react/components/team_members_modal.jsx2
-rw-r--r--web/react/components/user_settings/user_settings_advanced.jsx2
-rw-r--r--web/react/components/user_settings/user_settings_display.jsx9
-rw-r--r--web/react/components/user_settings/user_settings_modal.jsx2
25 files changed, 255 insertions, 220 deletions
diff --git a/web/react/components/access_history_modal.jsx b/web/react/components/access_history_modal.jsx
index 165d32339..deef92a54 100644
--- a/web/react/components/access_history_modal.jsx
+++ b/web/react/components/access_history_modal.jsx
@@ -32,7 +32,7 @@ export default class AccessHistoryModal extends React.Component {
onShow() {
AsyncClient.getAudits();
- $(ReactDOM.findDOMNode(this.refs.modalBody)).css('max-height', $(window).height() - 300);
+ $(ReactDOM.findDOMNode(this.refs.modalBody)).css('max-height', $(window).height() - 50);
if ($(window).width() > 768) {
$(ReactDOM.findDOMNode(this.refs.modalBody)).perfectScrollbar();
}
diff --git a/web/react/components/activity_log_modal.jsx b/web/react/components/activity_log_modal.jsx
index 869d648d2..200f4d724 100644
--- a/web/react/components/activity_log_modal.jsx
+++ b/web/react/components/activity_log_modal.jsx
@@ -51,7 +51,7 @@ export default class ActivityLogModal extends React.Component {
onShow() {
AsyncClient.getSessions();
- $(ReactDOM.findDOMNode(this.refs.modalBody)).css('max-height', $(window).height() - 300);
+ $(ReactDOM.findDOMNode(this.refs.modalBody)).css('max-height', $(window).height() - 50);
if ($(window).width() > 768) {
$(ReactDOM.findDOMNode(this.refs.modalBody)).perfectScrollbar();
}
diff --git a/web/react/components/center_panel.jsx b/web/react/components/center_panel.jsx
index 848e8952e..a1043431d 100644
--- a/web/react/components/center_panel.jsx
+++ b/web/react/components/center_panel.jsx
@@ -71,7 +71,8 @@ export default class CenterPanel extends React.Component {
href=''
onClick={handleClick}
>
- {'You are viewing the Archives. Click here to jump to recent messages.'}
+ {'You are viewing the Archives. Click here to jump to recent messages. '}
+ {<i className='fa fa-arrow-down'></i>}
</a>
</div>
);
diff --git a/web/react/components/channel_header.jsx b/web/react/components/channel_header.jsx
index 08c4a48ea..d5a46721e 100644
--- a/web/react/components/channel_header.jsx
+++ b/web/react/components/channel_header.jsx
@@ -40,7 +40,6 @@ export default class ChannelHeader extends React.Component {
const state = this.getStateFromStores();
state.showEditChannelPurposeModal = false;
- state.showInviteModal = false;
state.showMembersModal = false;
this.state = state;
}
@@ -201,13 +200,13 @@ export default class ChannelHeader extends React.Component {
key='add_members'
role='presentation'
>
- <a
+ <ToggleModalButton
role='menuitem'
- href='#'
- onClick={() => this.setState({showInviteModal: true})}
+ dialogType={ChannelInviteModal}
+ dialogProps={{channel}}
>
{'Add Members'}
- </a>
+ </ToggleModalButton>
</li>
);
@@ -402,13 +401,10 @@ export default class ChannelHeader extends React.Component {
onModalDismissed={() => this.setState({showEditChannelPurposeModal: false})}
channel={channel}
/>
- <ChannelInviteModal
- show={this.state.showInviteModal}
- onModalDismissed={() => this.setState({showInviteModal: false})}
- />
<ChannelMembersModal
show={this.state.showMembersModal}
onModalDismissed={() => this.setState({showMembersModal: false})}
+ channel={channel}
/>
</div>
);
diff --git a/web/react/components/channel_invite_modal.jsx b/web/react/components/channel_invite_modal.jsx
index 0518ccb86..56e2e53f9 100644
--- a/web/react/components/channel_invite_modal.jsx
+++ b/web/react/components/channel_invite_modal.jsx
@@ -53,15 +53,8 @@ export default class ChannelInviteModal extends React.Component {
return a.username.localeCompare(b.username);
});
- var channelName = '';
- if (ChannelStore.getCurrent()) {
- channelName = ChannelStore.getCurrent().display_name;
- }
-
return {
nonmembers,
- memberIds,
- channelName,
loading
};
}
@@ -94,28 +87,14 @@ export default class ChannelInviteModal extends React.Component {
}
}
handleInvite(userId) {
- // Make sure the user isn't already a member of the channel
- if (this.state.memberIds.indexOf(userId) > -1) {
- return;
- }
-
var data = {};
data.user_id = userId;
- Client.addChannelMember(ChannelStore.getCurrentId(), data,
+ Client.addChannelMember(
+ this.props.channel.id,
+ data,
() => {
- var nonmembers = this.state.nonmembers;
- var memberIds = this.state.memberIds;
-
- for (var i = 0; i < nonmembers.length; i++) {
- if (userId === nonmembers[i].id) {
- nonmembers[i].invited = true;
- memberIds.push(userId);
- break;
- }
- }
-
- this.setState({inviteError: null, memberIds, nonmembers});
+ this.setState({inviteError: null});
AsyncClient.getChannelExtraInfo();
},
(err) => {
@@ -157,10 +136,10 @@ export default class ChannelInviteModal extends React.Component {
<Modal
dialogClassName='more-modal'
show={this.props.show}
- onHide={this.props.onModalDismissed}
+ onHide={this.props.onHide}
>
<Modal.Header closeButton={true}>
- <Modal.Title>{'Add New Members to '}<span className='name'>{this.state.channelName}</span></Modal.Title>
+ <Modal.Title>{'Add New Members to '}<span className='name'>{this.props.channel.display_nam}</span></Modal.Title>
</Modal.Header>
<Modal.Body
ref='modalBody'
@@ -173,7 +152,7 @@ export default class ChannelInviteModal extends React.Component {
<button
type='button'
className='btn btn-default'
- onClick={this.props.onModalDismissed}
+ onClick={this.props.onHide}
>
{'Close'}
</button>
@@ -185,5 +164,6 @@ export default class ChannelInviteModal extends React.Component {
ChannelInviteModal.propTypes = {
show: React.PropTypes.bool.isRequired,
- onModalDismissed: React.PropTypes.func.isRequired
+ onHide: React.PropTypes.func.isRequired,
+ channel: React.PropTypes.object.isRequired
};
diff --git a/web/react/components/channel_members_modal.jsx b/web/react/components/channel_members_modal.jsx
index f07fc166a..d1b9df988 100644
--- a/web/react/components/channel_members_modal.jsx
+++ b/web/react/components/channel_members_modal.jsx
@@ -69,16 +69,9 @@ export default class ChannelMembersModal extends React.Component {
memberList.sort(compareByUsername);
nonmemberList.sort(compareByUsername);
- const channel = ChannelStore.getCurrent();
- let channelName = '';
- if (channel) {
- channelName = channel.display_name;
- }
-
return {
nonmemberList,
- memberList,
- channelName
+ memberList
};
}
onShow() {
@@ -169,7 +162,7 @@ export default class ChannelMembersModal extends React.Component {
onHide={this.props.onModalDismissed}
>
<Modal.Header closeButton={true}>
- <Modal.Title><span className='name'>{this.state.channelName}</span>{' Members'}</Modal.Title>
+ <Modal.Title><span className='name'>{this.props.channel.display_name}</span>{' Members'}</Modal.Title>
<a
className='btn btn-md btn-primary'
href='#'
@@ -205,7 +198,8 @@ export default class ChannelMembersModal extends React.Component {
</Modal>
<ChannelInviteModal
show={this.state.showInviteModal}
- onModalDismissed={() => this.setState({showInviteModal: false})}
+ onHide={() => this.setState({showInviteModal: false})}
+ channel={this.props.channel}
/>
</div>
);
@@ -218,5 +212,6 @@ ChannelMembersModal.defaultProps = {
ChannelMembersModal.propTypes = {
show: React.PropTypes.bool.isRequired,
- onModalDismissed: React.PropTypes.func.isRequired
+ onModalDismissed: React.PropTypes.func.isRequired,
+ channel: React.PropTypes.object.isRequired
};
diff --git a/web/react/components/invite_member_modal.jsx b/web/react/components/invite_member_modal.jsx
index 76f52faa9..25a915e22 100644
--- a/web/react/components/invite_member_modal.jsx
+++ b/web/react/components/invite_member_modal.jsx
@@ -143,7 +143,7 @@ export default class InviteMemberModal extends React.Component {
componentDidUpdate(prevProps, prevState) {
if (!prevState.show && this.state.show) {
- $(ReactDOM.findDOMNode(this.refs.modalBody)).css('max-height', $(window).height() - 300);
+ $(ReactDOM.findDOMNode(this.refs.modalBody)).css('max-height', $(window).height() - 50);
if ($(window).width() > 768) {
$(ReactDOM.findDOMNode(this.refs.modalBody)).perfectScrollbar();
}
diff --git a/web/react/components/member_list_item.jsx b/web/react/components/member_list_item.jsx
index f5d5ab28b..f7f77f48a 100644
--- a/web/react/components/member_list_item.jsx
+++ b/web/react/components/member_list_item.jsx
@@ -31,9 +31,7 @@ export default class MemberListItem extends React.Component {
var timestamp = UserStore.getCurrentUser().update_at;
var invite;
- if (member.invited && this.props.handleInvite) {
- invite = <span className='member-role'>Added</span>;
- } else if (this.props.handleInvite) {
+ if (this.props.handleInvite) {
invite = (
<a
onClick={this.handleInvite}
diff --git a/web/react/components/more_direct_channels.jsx b/web/react/components/more_direct_channels.jsx
index 9116dc8f1..cf40af6ae 100644
--- a/web/react/components/more_direct_channels.jsx
+++ b/web/react/components/more_direct_channels.jsx
@@ -166,7 +166,7 @@ export default class MoreDirectChannels extends React.Component {
componentDidUpdate(prevProps) {
if (!prevProps.show && this.props.show) {
- $(ReactDOM.findDOMNode(this.refs.userList)).css('max-height', $(window).height() - 300);
+ $(ReactDOM.findDOMNode(this.refs.userList)).css('max-height', $(window).height() - 50);
if ($(window).width() > 768) {
$(ReactDOM.findDOMNode(this.refs.userList)).perfectScrollbar();
}
diff --git a/web/react/components/navbar.jsx b/web/react/components/navbar.jsx
index 6c3bfc7db..3bdc9efac 100644
--- a/web/react/components/navbar.jsx
+++ b/web/react/components/navbar.jsx
@@ -44,7 +44,6 @@ export default class Navbar extends React.Component {
state.showEditChannelPurposeModal = false;
state.showEditChannelHeaderModal = false;
state.showMembersModal = false;
- state.showInviteModal = false;
this.state = state;
}
getStateFromStores() {
@@ -171,13 +170,13 @@ export default class Navbar extends React.Component {
if (!isDirect && !ChannelStore.isDefault(channel)) {
addMembersOption = (
<li role='presentation'>
- <a
+ <ToggleModalButton
role='menuitem'
- href='#'
- onClick={() => this.setState({showInviteModal: true})}
+ dialogType={ChannelInviteModal}
+ dialogProps={{channel}}
>
{'Add Members'}
- </a>
+ </ToggleModalButton>
</li>
);
@@ -475,10 +474,7 @@ export default class Navbar extends React.Component {
<ChannelMembersModal
show={this.state.showMembersModal}
onModalDismissed={() => this.setState({showMembersModal: false})}
- />
- <ChannelInviteModal
- show={this.state.showInviteModal}
- onModalDismissed={() => this.setState({showInviteModal: false})}
+ channel={{channel}}
/>
</div>
);
diff --git a/web/react/components/post_attachment_oembed.jsx b/web/react/components/post_attachment_oembed.jsx
index f544dbc88..13c32f744 100644
--- a/web/react/components/post_attachment_oembed.jsx
+++ b/web/react/components/post_attachment_oembed.jsx
@@ -20,8 +20,11 @@ export default class PostAttachmentOEmbed extends React.Component {
fetchData(link) {
if (!this.isLoading) {
this.isLoading = true;
+ let url = 'https://noembed.com/embed?nowrap=on';
+ url += '&url=' + encodeURIComponent(link);
+ url += '&maxheight=' + this.props.provider.height;
return $.ajax({
- url: 'https://noembed.com/embed?nowrap=on&url=' + encodeURIComponent(link),
+ url,
dataType: 'jsonp',
success: (result) => {
this.isLoading = false;
@@ -39,8 +42,18 @@ export default class PostAttachmentOEmbed extends React.Component {
}
render() {
+ let data = {};
+ let content;
if ($.isEmptyObject(this.state.data)) {
- return <div></div>;
+ content = <div style={{height: this.props.provider.height}}/>;
+ } else {
+ data = this.state.data;
+ content = (
+ <div
+ style={{height: this.props.provider.height}}
+ dangerouslySetInnerHTML={{__html: data.html}}
+ />
+ );
}
return (
@@ -57,18 +70,17 @@ export default class PostAttachmentOEmbed extends React.Component {
>
<a
className='attachment__title-link'
- href={this.state.data.url}
+ href={data.url}
target='_blank'
>
- {this.state.data.title}
+ {data.title}
</a>
</h1>
- <div>
- <div className={'attachment__body attachment__body--no_thumb'}>
- <div
- dangerouslySetInnerHTML={{__html: this.state.data.html}}
- >
- </div>
+ <div >
+ <div
+ className={'attachment__body attachment__body--no_thumb'}
+ >
+ {content}
</div>
</div>
</div>
@@ -79,5 +91,6 @@ export default class PostAttachmentOEmbed extends React.Component {
}
PostAttachmentOEmbed.propTypes = {
- link: React.PropTypes.string.isRequired
+ link: React.PropTypes.string.isRequired,
+ provider: React.PropTypes.object.isRequired
};
diff --git a/web/react/components/post_body.jsx b/web/react/components/post_body.jsx
index 27f7ad2de..296b9e7d7 100644
--- a/web/react/components/post_body.jsx
+++ b/web/react/components/post_body.jsx
@@ -6,6 +6,7 @@ import UserStore from '../stores/user_store.jsx';
import * as Utils from '../utils/utils.jsx';
import * as Emoji from '../utils/emoticons.jsx';
import Constants from '../utils/constants.jsx';
+const PreReleaseFeatures = Constants.PRE_RELEASE_FEATURES;
import * as TextFormatting from '../utils/text_formatting.jsx';
import twemoji from 'twemoji';
import PostBodyAdditionalContent from './post_body_additional_content.jsx';
@@ -109,11 +110,14 @@ export default class PostBody extends React.Component {
const trimmedLink = link.trim();
- if (this.checkForOembedContent(trimmedLink)) {
- post.props.oEmbedLink = trimmedLink;
- post.type = 'oEmbed';
- this.setState({post});
- return '';
+ if (Utils.isFeatureEnabled(PreReleaseFeatures.EMBED_PREVIEW)) {
+ const provider = this.getOembedProvider(trimmedLink);
+ if (provider != null) {
+ post.props.oEmbedLink = trimmedLink;
+ post.type = 'oEmbed';
+ this.setState({post, provider});
+ return '';
+ }
}
const embed = this.createYoutubeEmbed(link);
@@ -133,15 +137,15 @@ export default class PostBody extends React.Component {
return null;
}
- checkForOembedContent(link) {
+ getOembedProvider(link) {
for (let i = 0; i < providers.length; i++) {
for (let j = 0; j < providers[i].patterns.length; j++) {
if (link.match(providers[i].patterns[j])) {
- return true;
+ return providers[i];
}
}
}
- return false;
+ return null;
}
loadImg(src) {
@@ -399,6 +403,7 @@ export default class PostBody extends React.Component {
</div>
<PostBodyAdditionalContent
post={this.state.post}
+ provider={this.state.provider}
/>
{fileAttachmentHolder}
{this.embed}
diff --git a/web/react/components/post_body_additional_content.jsx b/web/react/components/post_body_additional_content.jsx
index e19bf51eb..7e6f3f037 100644
--- a/web/react/components/post_body_additional_content.jsx
+++ b/web/react/components/post_body_additional_content.jsx
@@ -32,6 +32,7 @@ export default class PostBodyAdditionalContent extends React.Component {
return (
<PostAttachmentOEmbed
key={'post_body_additional_content' + this.props.post.id}
+ provider={this.props.provider}
link={link}
/>
);
@@ -68,5 +69,6 @@ export default class PostBodyAdditionalContent extends React.Component {
}
PostBodyAdditionalContent.propTypes = {
- post: React.PropTypes.object.isRequired
-}; \ No newline at end of file
+ post: React.PropTypes.object.isRequired,
+ provider: React.PropTypes.object
+};
diff --git a/web/react/components/post_info.jsx b/web/react/components/post_info.jsx
index cedb2b59b..0b8b07d8c 100644
--- a/web/react/components/post_info.jsx
+++ b/web/react/components/post_info.jsx
@@ -9,14 +9,15 @@ import * as EventHelpers from '../dispatcher/event_helpers.jsx';
import Constants from '../utils/constants.jsx';
-const OverlayTrigger = ReactBootstrap.OverlayTrigger;
+const Overlay = ReactBootstrap.Overlay;
const Popover = ReactBootstrap.Popover;
export default class PostInfo extends React.Component {
constructor(props) {
super(props);
this.state = {
- copiedLink: false
+ copiedLink: false,
+ show: false
};
this.handlePermalinkCopy = this.handlePermalinkCopy.bind(this);
@@ -41,30 +42,37 @@ export default class PostInfo extends React.Component {
dataComments = this.props.commentCount;
}
- if (isOwner) {
+ if (this.props.allowReply === 'true') {
dropdownContents.push(
<li
- key='editPost'
+ key='replyLink'
role='presentation'
>
<a
+ className='link__reply theme'
href='#'
- role='menuitem'
- data-toggle='modal'
- data-target='#edit_post'
- data-refocusid='#post_textbox'
- data-title={type}
- data-message={post.message}
- data-postid={post.id}
- data-channelid={post.channel_id}
- data-comments={dataComments}
+ onClick={this.props.handleCommentClick}
>
- {'Edit'}
+ {'Reply'}
</a>
</li>
);
}
+ dropdownContents.push(
+ <li
+ key='copyLink'
+ role='presentation'
+ >
+ <a
+ href='#'
+ onClick={(e) => this.setState({target: e.target, show: !this.state.show})}
+ >
+ {'Permalink'}
+ </a>
+ </li>
+ );
+
if (isOwner || isAdmin) {
dropdownContents.push(
<li
@@ -82,18 +90,25 @@ export default class PostInfo extends React.Component {
);
}
- if (this.props.allowReply === 'true') {
+ if (isOwner) {
dropdownContents.push(
<li
- key='replyLink'
+ key='editPost'
role='presentation'
>
<a
- className='link__reply theme'
href='#'
- onClick={this.props.handleCommentClick}
+ role='menuitem'
+ data-toggle='modal'
+ data-target='#edit_post'
+ data-refocusid='#post_textbox'
+ data-title={type}
+ data-message={post.message}
+ data-postid={post.id}
+ data-channelid={post.channel_id}
+ data-comments={dataComments}
>
- {'Reply'}
+ {'Edit'}
</a>
</li>
);
@@ -121,6 +136,7 @@ export default class PostInfo extends React.Component {
</div>
);
}
+
handlePermalinkCopy() {
const textBox = $(ReactDOM.findDOMNode(this.refs.permalinkbox));
textBox.select();
@@ -128,7 +144,7 @@ export default class PostInfo extends React.Component {
try {
const successful = document.execCommand('copy');
if (successful) {
- this.setState({copiedLink: true});
+ this.setState({copiedLink: true, show: false});
} else {
this.setState({copiedLink: false});
}
@@ -197,6 +213,8 @@ export default class PostInfo extends React.Component {
</Popover>
);
+ const containerPadding = 20;
+
return (
<ul className='post__header post__header--info'>
<li className='col'>
@@ -206,18 +224,23 @@ export default class PostInfo extends React.Component {
</li>
<li className='col col__reply'>
{comments}
- <OverlayTrigger
- trigger='click'
- placement='left'
- rootClose={true}
- overlay={permalinkOverlay}
+ <div
+ className='dropdown'
+ ref='dotMenu'
>
- <i className={'permalink-icon fa fa-link ' + showCommentClass}/>
- </OverlayTrigger>
-
- <div className='dropdown'>
{dropdown}
</div>
+ <Overlay
+ show={this.state.show}
+ target={() => ReactDOM.findDOMNode(this.refs.dotMenu)}
+ onHide={() => this.setState({show: false})}
+ placement='left'
+ container={this}
+ containerPadding={containerPadding}
+ rootClose={true}
+ >
+ {permalinkOverlay}
+ </Overlay>
</li>
</ul>
);
diff --git a/web/react/components/posts_view_container.jsx b/web/react/components/posts_view_container.jsx
index 6d6694fec..631bd1872 100644
--- a/web/react/components/posts_view_container.jsx
+++ b/web/react/components/posts_view_container.jsx
@@ -3,7 +3,6 @@
import PostsView from './posts_view.jsx';
import LoadingScreen from './loading_screen.jsx';
-import ChannelInviteModal from './channel_invite_modal.jsx';
import ChannelStore from '../stores/channel_store.jsx';
import PostStore from '../stores/post_store.jsx';
@@ -13,7 +12,7 @@ import * as EventHelpers from '../dispatcher/event_helpers.jsx';
import Constants from '../utils/constants.jsx';
-import {createChannelIntroMessage} from '../utils/channel_intro_mssages.jsx';
+import {createChannelIntroMessage} from '../utils/channel_intro_messages.jsx';
export default class PostsViewContainer extends React.Component {
constructor() {
@@ -177,7 +176,7 @@ export default class PostsViewContainer extends React.Component {
loadMorePostsBottomClicked={() => {}}
showMoreMessagesTop={!this.state.atTop[this.state.currentChannelIndex]}
showMoreMessagesBottom={false}
- introText={channel ? createChannelIntroMessage(channel, () => this.setState({showInviteModal: true})) : null}
+ introText={channel ? createChannelIntroMessage(channel) : null}
messageSeparatorTime={this.state.currentLastViewed}
/>
);
@@ -194,10 +193,6 @@ export default class PostsViewContainer extends React.Component {
return (
<div id='post-list'>
{postListCtls}
- <ChannelInviteModal
- show={this.state.showInviteModal}
- onModalDismissed={() => this.setState({showInviteModal: false})}
- />
</div>
);
}
diff --git a/web/react/components/providers.json b/web/react/components/providers.json
index 5e4cbd656..33e377a39 100644
--- a/web/react/components/providers.json
+++ b/web/react/components/providers.json
@@ -3,265 +3,308 @@
"patterns": [
"http://(?:www\\.)?xkcd\\.com/\\d+/?"
],
- "name": "XKCD"
+ "name": "XKCD",
+ "height": 110
},
{
"patterns": [
"https?://soundcloud.com/.*/.*"
],
- "name": "SoundCloud"
+ "name": "SoundCloud",
+ "height": 110
},
{
"patterns": [
"https?://(?:www\\.)?flickr\\.com/.*",
"https?://flic\\.kr/p/[a-zA-Z0-9]+"
],
- "name": "Flickr"
+ "name": "Flickr",
+ "height": 110
},
{
"patterns": [
"http://www\\.ted\\.com/talks/.+\\.html"
],
- "name": "TED"
+ "name": "TED",
+ "height": 110
},
{
"patterns": [
"http://(?:www\\.)?theverge\\.com/\\d{4}/\\d{1,2}/\\d{1,2}/\\d+/[^/]+/?$"
],
- "name": "The Verge"
+ "name": "The Verge",
+ "height": 110
},
{
"patterns": [
"http://.*\\.viddler\\.com/.*"
],
- "name": "Viddler"
+ "name": "Viddler",
+ "height": 110
},
{
"patterns": [
"https?://(?:www\\.)?avclub\\.com/article/[^/]+/?$"
],
- "name": "The AV Club"
+ "name": "The AV Club",
+ "height": 110
},
{
"patterns": [
"https?://(?:www\\.)?wired\\.com/([^/]+/)?\\d+/\\d+/[^/]+/?$"
],
- "name": "Wired"
+ "name": "Wired",
+ "height": 110
},
{
"patterns": [
"http://www\\.theonion\\.com/articles/[^/]+/?"
],
- "name": "The Onion"
+ "name": "The Onion",
+ "height": 110
},
{
"patterns": [
"http://yfrog\\.com/[0-9a-zA-Z]+/?$"
],
- "name": "YFrog"
+ "name": "YFrog",
+ "height": 110
},
{
"patterns": [
"http://www\\.duffelblog\\.com/\\d{4}/\\d{1,2}/[^/]+/?$"
],
- "name": "The Duffel Blog"
+ "name": "The Duffel Blog",
+ "height": 110
},
{
"patterns": [
"http://www\\.clickhole\\.com/article/[^/]+/?"
],
- "name": "Clickhole"
+ "name": "Clickhole",
+ "height": 110
},
{
"patterns": [
"https?://(?:www.)?skitch.com/([^/]+)/[^/]+/.+",
"http://skit.ch/[^/]+"
],
- "name": "Skitch"
+ "name": "Skitch",
+ "height": 110
},
{
"patterns": [
"https?://(alpha|posts|photos)\\.app\\.net/.*"
],
- "name": "ADN"
+ "name": "ADN",
+ "height": 110
},
{
"patterns": [
"https?://gist\\.github\\.com/(?:[-0-9a-zA-Z]+/)?([0-9a-fA-f]+)"
],
- "name": "Gist"
+ "name": "Gist",
+ "height": 110
},
{
"patterns": [
"https?://www\\.(dropbox\\.com/s/.+\\.(?:jpg|png|gif))",
"https?://db\\.tt/[a-zA-Z0-9]+"
],
- "name": "Dropbox"
+ "name": "Dropbox",
+ "height": 110
},
{
"patterns": [
"https?://[^\\.]+\\.wikipedia\\.org/wiki/(?!Talk:)[^#]+(?:#(.+))?"
],
- "name": "Wikipedia"
+ "name": "Wikipedia",
+ "height": 110
},
{
"patterns": [
"http://www.traileraddict.com/trailer/[^/]+/trailer"
],
- "name": "TrailerAddict"
+ "name": "TrailerAddict",
+ "height": 110
},
{
"patterns": [
"http://lockerz\\.com/[sd]/\\d+"
],
- "name": "Lockerz"
+ "name": "Lockerz",
+ "height": 110
},
{
"patterns": [
"http://gifuk\\.com/s/[0-9a-f]{16}"
],
- "name": "GIFUK"
+ "name": "GIFUK",
+ "height": 110
},
{
"patterns": [
"http://trailers\\.apple\\.com/trailers/[^/]+/[^/]+"
],
- "name": "iTunes Movie Trailers"
+ "name": "iTunes Movie Trailers",
+ "height": 110
},
{
"patterns": [
"http://gfycat\\.com/([a-zA-Z]+)"
],
- "name": "Gfycat"
+ "name": "Gfycat",
+ "height": 110
},
{
"patterns": [
"http://bash\\.org/\\?(\\d+)"
],
- "name": "Bash.org"
+ "name": "Bash.org",
+ "height": 110
},
{
"patterns": [
"http://arstechnica\\.com/[^/]+/\\d+/\\d+/[^/]+/?$"
],
- "name": "Ars Technica"
+ "name": "Ars Technica",
+ "height": 110
},
{
"patterns": [
"http://imgur\\.com/gallery/[0-9a-zA-Z]+"
],
- "name": "Imgur"
+ "name": "Imgur",
+ "height": 110
},
{
"patterns": [
"http://www\\.asciiartfarts\\.com/[0-9]+\\.html"
],
- "name": "ASCII Art Farts"
+ "name": "ASCII Art Farts",
+ "height": 110
},
{
"patterns": [
"http://www\\.monoprice\\.com/products/product\\.asp\\?.*p_id=\\d+"
],
- "name": "Monoprice"
+ "name": "Monoprice",
+ "height": 110
},
{
"patterns": [
"http://boingboing\\.net/\\d{4}/\\d{2}/\\d{2}/[^/]+\\.html"
],
- "name": "Boing Boing"
+ "name": "Boing Boing",
+ "height": 110
},
{
"patterns": [
"https?://github\\.com/([^/]+)/([^/]+)/commit/(.+)",
"http://git\\.io/[_0-9a-zA-Z]+"
],
- "name": "Github Commit"
+ "name": "Github Commit",
+ "height": 110
},
{
"patterns": [
"https?://open\\.spotify\\.com/(track|album)/([0-9a-zA-Z]{22})"
],
- "name": "Spotify"
+ "name": "Spotify",
+ "height": 110
},
{
"patterns": [
"https?://path\\.com/p/([0-9a-zA-Z]+)$"
],
- "name": "Path"
+ "name": "Path",
+ "height": 110
},
{
"patterns": [
"http://www.funnyordie.com/videos/[^/]+/.+"
],
- "name": "Funny or Die"
+ "name": "Funny or Die",
+ "height": 110
},
{
"patterns": [
"http://(?:www\\.)?twitpic\\.com/([^/]+)"
],
- "name": "Twitpic"
+ "name": "Twitpic",
+ "height": 110
},
{
"patterns": [
"https?://www\\.giantbomb\\.com/videos/[^/]+/\\d+-\\d+/?"
],
- "name": "GiantBomb"
+ "name": "GiantBomb",
+ "height": 110
},
{
"patterns": [
"http://(?:www\\.)?beeradvocate\\.com/beer/profile/\\d+/\\d+"
],
- "name": "Beer Advocate"
+ "name": "Beer Advocate",
+ "height": 110
},
{
"patterns": [
"http://(?:www\\.)?imdb.com/title/(tt\\d+)"
],
- "name": "IMDB"
+ "name": "IMDB",
+ "height": 110
},
{
"patterns": [
"http://cl\\.ly/(?:image/)?[0-9a-zA-Z]+/?$"
],
- "name": "CloudApp"
+ "name": "CloudApp",
+ "height": 110
},
{
"patterns": [
"http://clyp\\.it/.*"
],
- "name": "Clyp"
+ "name": "Clyp",
+ "height": 110
},
{
"patterns": [
"http://www\\.hulu\\.com/watch/.*"
],
- "name": "Hulu"
+ "name": "Hulu",
+ "height": 110
},
{
"patterns": [
"https?://(?:www|mobile\\.)?twitter\\.com/(?:#!/)?[^/]+/status(?:es)?/(\\d+)/?$",
"https?://t\\.co/[a-zA-Z0-9]+"
],
- "name": "Twitter"
+ "name": "Twitter",
+ "height": 110
},
{
"patterns": [
"https?://(?:www\\.)?vimeo\\.com/.+"
],
- "name": "Vimeo"
+ "name": "Vimeo",
+ "height": 110
},
{
"patterns": [
"http://www\\.amazon\\.com/(?:.+/)?[gd]p/(?:product/)?(?:tags-on-product/)?([a-zA-Z0-9]+)",
"http://amzn\\.com/([^/]+)"
],
- "name": "Amazon"
+ "name": "Amazon",
+ "height": 110
},
{
"patterns": [
"http://qik\\.com/video/.*"
],
- "name": "Qik"
+ "name": "Qik",
+ "height": 110
},
{
"patterns": [
@@ -269,56 +312,65 @@
"http://www\\.rdio\\.com/artist/[^/]+/album/[^/]+/track/[^/]+/?",
"http://www\\.rdio\\.com/people/[^/]+/playlists/\\d+/[^/]+"
],
- "name": "Rdio"
+ "name": "Rdio",
+ "height": 110
},
{
"patterns": [
"http://www\\.slideshare\\.net/.*/.*"
],
- "name": "SlideShare"
+ "name": "SlideShare",
+ "height": 110
},
{
"patterns": [
"http://imgur\\.com/([0-9a-zA-Z]+)$"
],
- "name": "Imgur"
+ "name": "Imgur",
+ "height": 110
},
{
"patterns": [
"https?://instagr(?:\\.am|am\\.com)/p/.+"
],
- "name": "Instagram"
+ "name": "Instagram",
+ "height": 110
},
{
"patterns": [
"http://www\\.twitlonger\\.com/show/[a-zA-Z0-9]+",
"http://tl\\.gd/[^/]+"
],
- "name": "Twitlonger"
+ "name": "Twitlonger",
+ "height": 110
},
{
"patterns": [
"https?://vine.co/v/[a-zA-Z0-9]+"
],
- "name": "Vine"
+ "name": "Vine",
+ "height": 110
},
{
"patterns": [
"http://www\\.urbandictionary\\.com/define\\.php\\?term=.+"
],
- "name": "Urban Dictionary"
+ "name": "Urban Dictionary",
+ "height": 110
},
{
"patterns": [
"http://picplz\\.com/user/[^/]+/pic/[^/]+"
],
- "name": "Picplz"
+ "name": "Picplz",
+ "height": 110
},
{
"patterns": [
"https?://(?:www\\.)?twitter\\.com/(?:#!/)?[^/]+/status(?:es)?/(\\d+)/photo/\\d+(?:/large|/)?$",
"https?://pic\\.twitter\\.com/.+"
],
- "name": "Twitter"
+ "name": "Twitter",
+ "height": 110
}
-] \ No newline at end of file
+]
diff --git a/web/react/components/rhs_thread.jsx b/web/react/components/rhs_thread.jsx
index d111094e7..2edcd8b37 100644
--- a/web/react/components/rhs_thread.jsx
+++ b/web/react/components/rhs_thread.jsx
@@ -101,6 +101,15 @@ export default class RhsThread extends React.Component {
}
if (currentPosts.posts[currentPosts.order[0]].channel_id === currentSelected.posts[currentSelected.order[0]].channel_id) {
+ for (var key in currentSelected.posts) {
+ if (currentSelected.posts.hasOwnProperty(key)) {
+ var post = currentSelected.posts[key];
+ if (post.pending_post_id) {
+ Reflect.deleteProperty(currentSelected.posts, key);
+ }
+ }
+ }
+
for (var postId in currentPosts.posts) {
if (currentPosts.posts.hasOwnProperty(postId)) {
currentSelected.posts[postId] = currentPosts.posts[postId];
diff --git a/web/react/components/search_results_item.jsx b/web/react/components/search_results_item.jsx
index 6e17cfe32..1d4983026 100644
--- a/web/react/components/search_results_item.jsx
+++ b/web/react/components/search_results_item.jsx
@@ -65,7 +65,7 @@ export default class SearchResultsItem extends React.Component {
className='search-item__jump'
onClick={this.handleClick}
>
- {'[Jump]'}
+ {<i className='fa fa-mail-reply'></i>}
</a>
</li>
</ul>
diff --git a/web/react/components/suggestion/search_suggestion_list.jsx b/web/react/components/suggestion/search_suggestion_list.jsx
index 542d28ddd..3378a33a0 100644
--- a/web/react/components/suggestion/search_suggestion_list.jsx
+++ b/web/react/components/suggestion/search_suggestion_list.jsx
@@ -35,7 +35,7 @@ export default class SearchSuggestionList extends SuggestionList {
}
render() {
- if (this.state.items.length === 0 || !this.props.show) {
+ if (this.state.items.length === 0) {
return null;
}
diff --git a/web/react/components/suggestion/suggestion_box.jsx b/web/react/components/suggestion/suggestion_box.jsx
index 4ca461e82..ad8ad1e9e 100644
--- a/web/react/components/suggestion/suggestion_box.jsx
+++ b/web/react/components/suggestion/suggestion_box.jsx
@@ -13,7 +13,6 @@ export default class SuggestionBox extends React.Component {
super(props);
this.handleDocumentClick = this.handleDocumentClick.bind(this);
- this.handleFocus = this.handleFocus.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleCompleteWord = this.handleCompleteWord.bind(this);
@@ -21,10 +20,6 @@ export default class SuggestionBox extends React.Component {
this.handlePretextChanged = this.handlePretextChanged.bind(this);
this.suggestionId = Utils.generateId();
-
- this.state = {
- focused: false
- };
}
componentDidMount() {
@@ -49,27 +44,11 @@ export default class SuggestionBox extends React.Component {
}
handleDocumentClick(e) {
- if (!this.state.focused) {
- return;
- }
-
const container = $(ReactDOM.findDOMNode(this));
if (!(container.is(e.target) || container.has(e.target).length > 0)) {
// we can't just use blur for this because it fires and hides the children before
// their click handlers can be called
- this.setState({
- focused: false
- });
- }
- }
-
- handleFocus() {
- this.setState({
- focused: true
- });
-
- if (this.props.onFocus) {
- this.props.onFocus();
+ EventHelpers.emitClearSuggestions(this.suggestionId);
}
}
@@ -115,7 +94,7 @@ export default class SuggestionBox extends React.Component {
} else if (e.which === KeyCodes.DOWN) {
EventHelpers.emitSelectNextSuggestion(this.suggestionId);
e.preventDefault();
- } else if (e.which === KeyCodes.ENTER || (e.which === KeyCodes.SPACE && SuggestionStore.shouldCompleteOnSpace(this.suggestionId))) {
+ } else if (e.which === KeyCodes.ENTER || e.which === KeyCodes.TAB || (e.which === KeyCodes.SPACE && SuggestionStore.shouldCompleteOnSpace(this.suggestionId))) {
EventHelpers.emitCompleteWordSuggestion(this.suggestionId);
e.preventDefault();
} else if (this.props.onKeyDown) {
@@ -134,7 +113,6 @@ export default class SuggestionBox extends React.Component {
render() {
const newProps = Object.assign({}, this.props, {
- onFocus: this.handleFocus,
onChange: this.handleChange,
onKeyDown: this.handleKeyDown
});
@@ -162,10 +140,7 @@ export default class SuggestionBox extends React.Component {
return (
<div>
{textbox}
- <SuggestionListComponent
- suggestionId={this.suggestionId}
- show={this.state.focused}
- />
+ <SuggestionListComponent suggestionId={this.suggestionId} />
</div>
);
}
@@ -184,6 +159,5 @@ SuggestionBox.propTypes = {
// explicitly name any input event handlers we override and need to manually call
onChange: React.PropTypes.func,
- onKeyDown: React.PropTypes.func,
- onFocus: React.PropTypes.func
+ onKeyDown: React.PropTypes.func
};
diff --git a/web/react/components/suggestion/suggestion_list.jsx b/web/react/components/suggestion/suggestion_list.jsx
index 87021fd94..e3ccd0f08 100644
--- a/web/react/components/suggestion/suggestion_list.jsx
+++ b/web/react/components/suggestion/suggestion_list.jsx
@@ -82,7 +82,7 @@ export default class SuggestionList extends React.Component {
}
render() {
- if (this.state.items.length === 0 || !this.props.show) {
+ if (this.state.items.length === 0) {
return null;
}
@@ -121,6 +121,5 @@ export default class SuggestionList extends React.Component {
}
SuggestionList.propTypes = {
- suggestionId: React.PropTypes.string.isRequired,
- show: React.PropTypes.bool.isRequired
+ suggestionId: React.PropTypes.string.isRequired
};
diff --git a/web/react/components/team_members_modal.jsx b/web/react/components/team_members_modal.jsx
index 0a30a2202..eed4a1f19 100644
--- a/web/react/components/team_members_modal.jsx
+++ b/web/react/components/team_members_modal.jsx
@@ -26,7 +26,7 @@ export default class TeamMembersModal extends React.Component {
}
onShow() {
- $(ReactDOM.findDOMNode(this.refs.modalBody)).css('max-height', $(window).height() - 300);
+ $(ReactDOM.findDOMNode(this.refs.modalBody)).css('max-height', $(window).height() - 50);
if ($(window).width() > 768) {
$(ReactDOM.findDOMNode(this.refs.modalBody)).perfectScrollbar();
}
diff --git a/web/react/components/user_settings/user_settings_advanced.jsx b/web/react/components/user_settings/user_settings_advanced.jsx
index b4d34c658..c15936ccd 100644
--- a/web/react/components/user_settings/user_settings_advanced.jsx
+++ b/web/react/components/user_settings/user_settings_advanced.jsx
@@ -195,7 +195,7 @@ export default class AdvancedSettingsDisplay extends React.Component {
inputs.push(
<div key='advancedPreviewFeatures_helptext'>
<br/>
- {'Check any pre-released features you\'d like to preview.'}
+ {'Check any pre-released features you\'d like to preview. You may also need to refresh the page before the setting will take effect.'}
</div>
);
diff --git a/web/react/components/user_settings/user_settings_display.jsx b/web/react/components/user_settings/user_settings_display.jsx
index dc3865c68..c464258de 100644
--- a/web/react/components/user_settings/user_settings_display.jsx
+++ b/web/react/components/user_settings/user_settings_display.jsx
@@ -241,7 +241,7 @@ export default class UserSettingsDisplay extends React.Component {
const inputs = [
<div key='userDisplayNameOptions'>
<div
- className='input-group theme-group dropdown'
+ className='dropdown'
>
<select
className='form-control'
@@ -251,9 +251,6 @@ export default class UserSettingsDisplay extends React.Component {
>
{options}
</select>
- <span className={'input-group-addon ' + Constants.FONTS[this.state.selectedFont]}>
- {this.state.selectedFont}
- </span>
</div>
<div><br/>{'Select the font displayed in the Mattermost user interface.'}</div>
</div>
@@ -312,12 +309,12 @@ export default class UserSettingsDisplay extends React.Component {
<div className='user-settings'>
<h3 className='tab-header'>{'Display Settings'}</h3>
<div className='divider-dark first'/>
+ {fontSection}
+ <div className='divider-dark'/>
{clockSection}
<div className='divider-dark'/>
{nameFormatSection}
<div className='divider-dark'/>
- {fontSection}
- <div className='divider-dark'/>
</div>
</div>
);
diff --git a/web/react/components/user_settings/user_settings_modal.jsx b/web/react/components/user_settings/user_settings_modal.jsx
index f9d03f56d..97c601b5e 100644
--- a/web/react/components/user_settings/user_settings_modal.jsx
+++ b/web/react/components/user_settings/user_settings_modal.jsx
@@ -47,7 +47,7 @@ export default class UserSettingsModal extends React.Component {
}
handleShow() {
- $(ReactDOM.findDOMNode(this.refs.modalBody)).css('max-height', $(window).height() - 300);
+ $(ReactDOM.findDOMNode(this.refs.modalBody)).css('max-height', $(window).height() - 50);
if ($(window).width() > 768) {
$(ReactDOM.findDOMNode(this.refs.modalBody)).perfectScrollbar();
}