From d3ed791ab52eaddb7690869bb1cd982453badd95 Mon Sep 17 00:00:00 2001 From: Florian Orben Date: Sat, 31 Oct 2015 03:22:02 +0100 Subject: attachments frontend --- web/react/components/create_comment.jsx | 1 + web/react/components/create_post.jsx | 1 + web/react/components/post_attachment.jsx | 240 ++++++++++++++++++++++++++ web/react/components/post_attachment_list.jsx | 32 ++++ web/react/components/post_body.jsx | 11 ++ 5 files changed, 285 insertions(+) create mode 100644 web/react/components/post_attachment.jsx create mode 100644 web/react/components/post_attachment_list.jsx (limited to 'web/react/components') diff --git a/web/react/components/create_comment.jsx b/web/react/components/create_comment.jsx index 058594165..6fb473ae6 100644 --- a/web/react/components/create_comment.jsx +++ b/web/react/components/create_comment.jsx @@ -109,6 +109,7 @@ export default class CreateComment extends React.Component { post.pending_post_id = `${userId}:${time}`; post.user_id = userId; post.create_at = time; + post.attachments = []; PostStore.storePendingPost(post); PostStore.storeCommentDraft(this.props.rootId, null); diff --git a/web/react/components/create_post.jsx b/web/react/components/create_post.jsx index 5a69c9bfb..90ba47718 100644 --- a/web/react/components/create_post.jsx +++ b/web/react/components/create_post.jsx @@ -173,6 +173,7 @@ export default class CreatePost extends React.Component { post.create_at = time; post.root_id = this.state.rootId; post.parent_id = this.state.parentId; + post.attachments = []; const channel = ChannelStore.get(this.state.channelId); diff --git a/web/react/components/post_attachment.jsx b/web/react/components/post_attachment.jsx new file mode 100644 index 000000000..6bc9ade47 --- /dev/null +++ b/web/react/components/post_attachment.jsx @@ -0,0 +1,240 @@ +// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +const TextFormatting = require('../utils/text_formatting.jsx'); + +export default class PostAttachment extends React.Component { + constructor(props) { + super(props); + + this.getFieldsTable = this.getFieldsTable.bind(this); + } + + getFieldsTable() { + const fields = this.props.attachment.fields; + if (!fields || !fields.length) { + return ''; + } + + const compactTable = fields.filter((field) => field.short).length > 0; + let tHead; + let tBody; + + if (compactTable) { + let headerCols = []; + let bodyCols = []; + + fields.forEach((field, i) => { + headerCols.push( + + {field.title} + + ); + bodyCols.push( + + + ); + }); + + tHead = ( + + {headerCols} + + ); + tBody = ( + + {bodyCols} + + ); + } else { + tBody = []; + + fields.forEach((field, i) => { + tBody.push( + + + {field.title} + + + + + ); + }); + } + + return ( + + + {tHead} + + + {tBody} + +
+ ); + } + + render() { + const data = this.props.attachment; + + let preText; + if (data.pretext) { + preText = ( +
+
+ ); + } + + let author = []; + if (data.author_name || data.author_icon) { + if (data.author_icon) { + author.push( + + ); + } + if (data.author_name) { + author.push( + + {data.author_name} + + ); + } + } + if (data.author_link) { + author = ( + + {author} + + ); + } + + let title; + if (data.title) { + if (data.title_link) { + title = ( +

+ + {data.title} + +

+ ); + } else { + title = ( +

+ {data.title} +

+ ); + } + } + + let text; + if (data.text) { + text = ( +
+
+ ); + } + + let image; + if (data.image_url) { + image = ( + + ); + } + + let thumb; + if (data.thumb_url) { + thumb = ( +
+ +
+ ); + } + + const fields = this.getFieldsTable(); + + let useBorderStyle; + if (data.color && data.color[0] === '#') { + useBorderStyle = {borderLeftColor: data.color}; + } + + return ( +
+ {preText} +
+
+ {author} + {title} +
+
+ {text} + {image} + {fields} +
+ {thumb} +
+
+
+
+
+ ); + } +} + +PostAttachment.propTypes = { + attachment: React.PropTypes.object.isRequired +}; \ No newline at end of file diff --git a/web/react/components/post_attachment_list.jsx b/web/react/components/post_attachment_list.jsx new file mode 100644 index 000000000..03b866656 --- /dev/null +++ b/web/react/components/post_attachment_list.jsx @@ -0,0 +1,32 @@ +// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +const PostAttachment = require('./post_attachment.jsx'); + +export default class PostAttachmentList extends React.Component { + constructor(props) { + super(props); + } + + render() { + let content = []; + this.props.attachments.forEach((attachment, i) => { + content.push( + + ); + }); + + return ( +
+ {content} +
+ ); + } +} + +PostAttachmentList.propTypes = { + attachments: React.PropTypes.array.isRequired +}; diff --git a/web/react/components/post_body.jsx b/web/react/components/post_body.jsx index e4094daf3..4da13dace 100644 --- a/web/react/components/post_body.jsx +++ b/web/react/components/post_body.jsx @@ -7,6 +7,7 @@ const Utils = require('../utils/utils.jsx'); const Constants = require('../utils/constants.jsx'); const TextFormatting = require('../utils/text_formatting.jsx'); const twemoji = require('twemoji'); +const PostAttachmentList = require('./post_attachment_list.jsx'); export default class PostBody extends React.Component { constructor(props) { @@ -316,6 +317,15 @@ export default class PostBody extends React.Component { ); } + let postAttachments = ''; + if (post.attachments && post.attachments.length) { + postAttachments = ( + + ); + } + return (
{comment} @@ -331,6 +341,7 @@ export default class PostBody extends React.Component { dangerouslySetInnerHTML={{__html: TextFormatting.formatText(this.state.message)}} />
+ {postAttachments} {fileAttachmentHolder} {embed} -- cgit v1.2.3-1-g7c22 From 4b6eb56415c2085bc9078836b70b833b1e01a60d Mon Sep 17 00:00:00 2001 From: Florian Orben Date: Sat, 31 Oct 2015 04:46:35 +0100 Subject: collapse text after 700 chars or 5 line breaks --- web/react/components/post_attachment.jsx | 59 ++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) (limited to 'web/react/components') diff --git a/web/react/components/post_attachment.jsx b/web/react/components/post_attachment.jsx index 6bc9ade47..2d6b47f03 100644 --- a/web/react/components/post_attachment.jsx +++ b/web/react/components/post_attachment.jsx @@ -8,6 +8,60 @@ export default class PostAttachment extends React.Component { super(props); this.getFieldsTable = this.getFieldsTable.bind(this); + this.getInitState = this.getInitState.bind(this); + this.shouldCollapse = this.shouldCollapse.bind(this); + this.toggleCollapseState = this.toggleCollapseState.bind(this); + } + + componentDidMount() { + $(this.refs.attachment).on('click', '.attachment-link-more', this.toggleCollapseState); + } + + componentWillUnmount() { + $(this.refs.attachment).off('click', '.attachment-link-more', this.toggleCollapseState); + } + + componentWillMount() { + this.setState(this.getInitState()); + } + + getInitState() { + const shouldCollapse = this.shouldCollapse(); + const text = TextFormatting.formatText(this.props.attachment.text || ''); + const uncollapsedText = text + (shouldCollapse ? '▲ collapse text' : ''); + const collapsedText = shouldCollapse ? this.getCollapsedText() : text; + + return { + shouldCollapse, + collapsedText, + uncollapsedText, + text: shouldCollapse ? collapsedText : uncollapsedText, + collapsed: shouldCollapse + }; + } + + toggleCollapseState(e) { + e.preventDefault(); + + let state = this.state; + state.text = state.collapsed ? state.uncollapsedText : state.collapsedText; + state.collapsed = !state.collapsed; + this.setState(state); + } + + shouldCollapse() { + return (this.props.attachment.text.match(/\n/g) || []).length >= 5 || this.props.attachment.text.length > 700; + } + + getCollapsedText() { + let text = this.props.attachment.text || ''; + if ((text.match(/\n/g) || []).length >= 5) { + text = text.split('\n').splice(0, 5).join('\n'); + } else if (text.length > 700) { + text = text.substr(0, 700); + } + + return TextFormatting.formatText(text) + '▼ read more'; } getFieldsTable() { @@ -169,7 +223,7 @@ export default class PostAttachment extends React.Component { text = (
); @@ -208,11 +262,12 @@ export default class PostAttachment extends React.Component { return (
{preText}
{author} -- cgit v1.2.3-1-g7c22 From b085bc2d56bdc98101b8cb50848aee248d42af28 Mon Sep 17 00:00:00 2001 From: Florian Orben Date: Thu, 5 Nov 2015 23:32:44 +0100 Subject: PLT-857: Support for Incoming Webhooks - Try #2 --- web/react/components/post_body.jsx | 15 ++---- .../components/post_body_additional_content.jsx | 56 ++++++++++++++++++++++ 2 files changed, 60 insertions(+), 11 deletions(-) create mode 100644 web/react/components/post_body_additional_content.jsx (limited to 'web/react/components') diff --git a/web/react/components/post_body.jsx b/web/react/components/post_body.jsx index 4da13dace..5a157b792 100644 --- a/web/react/components/post_body.jsx +++ b/web/react/components/post_body.jsx @@ -7,7 +7,7 @@ const Utils = require('../utils/utils.jsx'); const Constants = require('../utils/constants.jsx'); const TextFormatting = require('../utils/text_formatting.jsx'); const twemoji = require('twemoji'); -const PostAttachmentList = require('./post_attachment_list.jsx'); +const PostBodyAdditionalContent = require('./post_body_additional_content.jsx'); export default class PostBody extends React.Component { constructor(props) { @@ -317,15 +317,6 @@ export default class PostBody extends React.Component { ); } - let postAttachments = ''; - if (post.attachments && post.attachments.length) { - postAttachments = ( - - ); - } - return (
{comment} @@ -341,7 +332,9 @@ export default class PostBody extends React.Component { dangerouslySetInnerHTML={{__html: TextFormatting.formatText(this.state.message)}} />
- {postAttachments} + {fileAttachmentHolder} {embed}
diff --git a/web/react/components/post_body_additional_content.jsx b/web/react/components/post_body_additional_content.jsx new file mode 100644 index 000000000..8189ba2d3 --- /dev/null +++ b/web/react/components/post_body_additional_content.jsx @@ -0,0 +1,56 @@ +// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +const PostAttachmentList = require('./post_attachment_list.jsx'); + +export default class PostBodyAdditionalContent extends React.Component { + constructor(props) { + super(props); + + this.getSlackAttachment = this.getSlackAttachment.bind(this); + this.getComponent = this.getComponent.bind(this); + } + + componentWillMount() { + this.setState({type: this.props.post.type, shouldRender: Boolean(this.props.post.type)}); + } + + getSlackAttachment() { + const attachments = this.props.post.props && this.props.post.props.attachments || []; + return ( + + ); + } + + getComponent() { + switch (this.state.type) { + case 'slack_attachment': + return this.getSlackAttachment(); + } + } + + render() { + let content = []; + + if (this.state.shouldRender) { + const component = this.getComponent(); + + if (component) { + content = component; + } + } + + return ( +
+ {content} +
+ ); + } +} + +PostBodyAdditionalContent.propTypes = { + post: React.PropTypes.object.isRequired +}; \ No newline at end of file -- cgit v1.2.3-1-g7c22 From 4dedb14467ee79f21cdaa8db696c4cac0fb120de Mon Sep 17 00:00:00 2001 From: Florian Orben Date: Thu, 5 Nov 2015 23:57:01 +0100 Subject: remove two unused assignments --- web/react/components/create_comment.jsx | 1 - web/react/components/create_post.jsx | 1 - 2 files changed, 2 deletions(-) (limited to 'web/react/components') diff --git a/web/react/components/create_comment.jsx b/web/react/components/create_comment.jsx index 6fb473ae6..058594165 100644 --- a/web/react/components/create_comment.jsx +++ b/web/react/components/create_comment.jsx @@ -109,7 +109,6 @@ export default class CreateComment extends React.Component { post.pending_post_id = `${userId}:${time}`; post.user_id = userId; post.create_at = time; - post.attachments = []; PostStore.storePendingPost(post); PostStore.storeCommentDraft(this.props.rootId, null); diff --git a/web/react/components/create_post.jsx b/web/react/components/create_post.jsx index 90ba47718..5a69c9bfb 100644 --- a/web/react/components/create_post.jsx +++ b/web/react/components/create_post.jsx @@ -173,7 +173,6 @@ export default class CreatePost extends React.Component { post.create_at = time; post.root_id = this.state.rootId; post.parent_id = this.state.parentId; - post.attachments = []; const channel = ChannelStore.get(this.state.channelId); -- cgit v1.2.3-1-g7c22