MM-10273 Add hashtag support (#2106)
* MM-10273 Add hashtag support * Put hashtag search in a proper modal * Change hashtag search style to match regular search * Move Hashtag component and explicitly pass props * Add unit tests for Hashtag component * Fix merge conflict
This commit is contained in:
parent
07f88071c6
commit
578f204784
14 changed files with 291 additions and 15 deletions
70
app/components/markdown/__snapshots__/hashtag.test.js.snap
Normal file
70
app/components/markdown/__snapshots__/hashtag.test.js.snap
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Hashtag should match snapshot 1`] = `
|
||||
ShallowWrapper {
|
||||
"length": 1,
|
||||
Symbol(enzyme.__root__): [Circular],
|
||||
Symbol(enzyme.__unrendered__): <Hashtag
|
||||
hashtag="test"
|
||||
linkStyle={
|
||||
Object {
|
||||
"color": "red",
|
||||
}
|
||||
}
|
||||
navigator={Object {}}
|
||||
theme={Object {}}
|
||||
/>,
|
||||
Symbol(enzyme.__renderer__): Object {
|
||||
"batchedUpdates": [Function],
|
||||
"getNode": [Function],
|
||||
"render": [Function],
|
||||
"simulateEvent": [Function],
|
||||
"unmount": [Function],
|
||||
},
|
||||
Symbol(enzyme.__node__): Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "class",
|
||||
"props": Object {
|
||||
"accessible": true,
|
||||
"allowFontScaling": true,
|
||||
"children": "#test",
|
||||
"ellipsizeMode": "tail",
|
||||
"onPress": [Function],
|
||||
"style": Object {
|
||||
"color": "red",
|
||||
},
|
||||
},
|
||||
"ref": null,
|
||||
"rendered": "#test",
|
||||
"type": [Function],
|
||||
},
|
||||
Symbol(enzyme.__nodes__): Array [
|
||||
Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "class",
|
||||
"props": Object {
|
||||
"accessible": true,
|
||||
"allowFontScaling": true,
|
||||
"children": "#test",
|
||||
"ellipsizeMode": "tail",
|
||||
"onPress": [Function],
|
||||
"style": Object {
|
||||
"color": "red",
|
||||
},
|
||||
},
|
||||
"ref": null,
|
||||
"rendered": "#test",
|
||||
"type": [Function],
|
||||
},
|
||||
],
|
||||
Symbol(enzyme.__options__): Object {
|
||||
"adapter": ReactSixteenAdapter {
|
||||
"options": Object {
|
||||
"enableComponentDidUpdateOnSetState": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
`;
|
||||
60
app/components/markdown/hashtag.js
Normal file
60
app/components/markdown/hashtag.js
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import {intlShape} from 'react-intl';
|
||||
import {Text} from 'react-native';
|
||||
|
||||
import CustomPropTypes from 'app/constants/custom_prop_types';
|
||||
|
||||
export default class Hashtag extends React.PureComponent {
|
||||
static propTypes = {
|
||||
hashtag: PropTypes.string.isRequired,
|
||||
linkStyle: CustomPropTypes.Style.isRequired,
|
||||
onHashtagPress: PropTypes.func,
|
||||
navigator: PropTypes.object.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
intl: intlShape,
|
||||
};
|
||||
|
||||
handlePress = () => {
|
||||
if (this.props.onHashtagPress) {
|
||||
this.props.onHashtagPress(this.props.hashtag);
|
||||
return;
|
||||
}
|
||||
|
||||
const options = {
|
||||
screen: 'Search',
|
||||
animated: true,
|
||||
backButtonTitle: '',
|
||||
passProps: {
|
||||
initialValue: '#' + this.props.hashtag,
|
||||
},
|
||||
navigatorStyle: {
|
||||
navBarHidden: true,
|
||||
screenBackgroundColor: this.props.theme.centerChannelBg,
|
||||
},
|
||||
};
|
||||
|
||||
// Close thread view, permalink view, etc
|
||||
this.props.navigator.dismissAllModals();
|
||||
this.props.navigator.popToRoot();
|
||||
|
||||
this.props.navigator.showModal(options);
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Text
|
||||
style={this.props.linkStyle}
|
||||
onPress={this.handlePress}
|
||||
>
|
||||
{`#${this.props.hashtag}`}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
}
|
||||
69
app/components/markdown/hashtag.test.js
Normal file
69
app/components/markdown/hashtag.test.js
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {shallow} from 'enzyme';
|
||||
import React from 'react';
|
||||
import {Text} from 'react-native';
|
||||
|
||||
import Hashtag from './hashtag';
|
||||
|
||||
describe('Hashtag', () => {
|
||||
const baseProps = {
|
||||
hashtag: 'test',
|
||||
linkStyle: {color: 'red'},
|
||||
navigator: {},
|
||||
theme: {},
|
||||
};
|
||||
|
||||
test('should match snapshot', () => {
|
||||
const wrapper = shallow(<Hashtag {...baseProps}/>);
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should open hashtag search on click', () => {
|
||||
const props = {
|
||||
...baseProps,
|
||||
navigator: {
|
||||
dismissAllModals: jest.fn(),
|
||||
popToRoot: jest.fn(),
|
||||
showModal: jest.fn(),
|
||||
},
|
||||
};
|
||||
|
||||
const wrapper = shallow(<Hashtag {...props}/>);
|
||||
|
||||
wrapper.find(Text).simulate('press');
|
||||
|
||||
expect(props.navigator.dismissAllModals).toHaveBeenCalled();
|
||||
expect(props.navigator.popToRoot).toHaveBeenCalled();
|
||||
expect(props.navigator.showModal).toHaveBeenCalledWith(expect.objectContaining({
|
||||
screen: 'Search',
|
||||
passProps: {
|
||||
initialValue: '#test',
|
||||
},
|
||||
}));
|
||||
});
|
||||
|
||||
test('should call onHashtagPress if provided', () => {
|
||||
const props = {
|
||||
...baseProps,
|
||||
navigator: {
|
||||
dismissAllModals: jest.fn(),
|
||||
popToRoot: jest.fn(),
|
||||
showModal: jest.fn(),
|
||||
},
|
||||
onHashtagPress: jest.fn(),
|
||||
};
|
||||
|
||||
const wrapper = shallow(<Hashtag {...props}/>);
|
||||
|
||||
wrapper.find(Text).simulate('press');
|
||||
|
||||
expect(props.navigator.dismissAllModals).not.toBeCalled();
|
||||
expect(props.navigator.popToRoot).not.toBeCalled();
|
||||
expect(props.navigator.showModal).not.toBeCalled();
|
||||
|
||||
expect(props.onHashtagPress).toBeCalled();
|
||||
});
|
||||
});
|
||||
|
|
@ -15,6 +15,7 @@ import AtMention from 'app/components/at_mention';
|
|||
import ChannelLink from 'app/components/channel_link';
|
||||
import Emoji from 'app/components/emoji';
|
||||
import FormattedText from 'app/components/formatted_text';
|
||||
import Hashtag from 'app/components/hashtag';
|
||||
import CustomPropTypes from 'app/constants/custom_prop_types';
|
||||
import {blendColors, concatStyles, makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
import {getScheme} from 'app/utils/url';
|
||||
|
|
@ -41,6 +42,7 @@ export default class Markdown extends PureComponent {
|
|||
isSearchResult: PropTypes.bool,
|
||||
navigator: PropTypes.object.isRequired,
|
||||
onChannelLinkPress: PropTypes.func,
|
||||
onHashtagPress: PropTypes.func,
|
||||
onLongPress: PropTypes.func,
|
||||
onPermalinkPress: PropTypes.func,
|
||||
onPostPress: PropTypes.func,
|
||||
|
|
@ -88,6 +90,7 @@ export default class Markdown extends PureComponent {
|
|||
atMention: this.renderAtMention,
|
||||
channelLink: this.renderChannelLink,
|
||||
emoji: this.renderEmoji,
|
||||
hashtag: this.renderHashtag,
|
||||
|
||||
paragraph: this.renderParagraph,
|
||||
heading: this.renderHeading,
|
||||
|
|
@ -213,6 +216,18 @@ export default class Markdown extends PureComponent {
|
|||
);
|
||||
}
|
||||
|
||||
renderHashtag = ({hashtag}) => {
|
||||
return (
|
||||
<Hashtag
|
||||
hashtag={hashtag}
|
||||
linkStyle={this.props.textStyles.link}
|
||||
onHashtagPress={this.props.onHashtagPress}
|
||||
navigator={this.props.navigator}
|
||||
theme={this.props.theme}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderParagraph = ({children, first}) => {
|
||||
if (!children || children.length === 0) {
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ export default class MessageAttachments extends PureComponent {
|
|||
blockStyles: PropTypes.object,
|
||||
postId: PropTypes.string.isRequired,
|
||||
navigator: PropTypes.object.isRequired,
|
||||
onHashtagPress: PropTypes.func,
|
||||
onLongPress: PropTypes.func.isRequired,
|
||||
onPermalinkPress: PropTypes.func,
|
||||
theme: PropTypes.object,
|
||||
|
|
@ -28,6 +29,7 @@ export default class MessageAttachments extends PureComponent {
|
|||
baseTextStyle,
|
||||
blockStyles,
|
||||
navigator,
|
||||
onHashtagPress,
|
||||
onLongPress,
|
||||
onPermalinkPress,
|
||||
postId,
|
||||
|
|
@ -44,6 +46,7 @@ export default class MessageAttachments extends PureComponent {
|
|||
blockStyles={blockStyles}
|
||||
key={'att_' + i}
|
||||
navigator={navigator}
|
||||
onHashtagPress={onHashtagPress}
|
||||
onLongPress={onLongPress}
|
||||
onPermalinkPress={onPermalinkPress}
|
||||
postId={postId}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ export default class Post extends PureComponent {
|
|||
canEdit: PropTypes.bool.isRequired,
|
||||
canEditUntil: PropTypes.number.isRequired,
|
||||
canDelete: PropTypes.bool.isRequired,
|
||||
onHashtagPress: PropTypes.func,
|
||||
onPermalinkPress: PropTypes.func,
|
||||
shouldRenderReplyButton: PropTypes.bool,
|
||||
showAddReaction: PropTypes.bool,
|
||||
|
|
@ -349,6 +350,7 @@ export default class Post extends PureComponent {
|
|||
highlight,
|
||||
isLastReply,
|
||||
isSearchResult,
|
||||
onHashtagPress,
|
||||
onPermalinkPress,
|
||||
post,
|
||||
renderReplies,
|
||||
|
|
@ -448,6 +450,7 @@ export default class Post extends PureComponent {
|
|||
onCopyPermalink={this.handleCopyPermalink}
|
||||
onCopyText={this.handleCopyText}
|
||||
onFailedPostPress={this.handleFailedPostPress}
|
||||
onHashtagPress={onHashtagPress}
|
||||
onPermalinkPress={onPermalinkPress}
|
||||
onPostDelete={this.handlePostDelete}
|
||||
onPostEdit={this.handlePostEdit}
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ export default class PostBody extends PureComponent {
|
|||
onCopyPermalink: PropTypes.func,
|
||||
onCopyText: PropTypes.func,
|
||||
onFailedPostPress: PropTypes.func,
|
||||
onHashtagPress: PropTypes.func,
|
||||
onPermalinkPress: PropTypes.func,
|
||||
onPostDelete: PropTypes.func,
|
||||
onPostEdit: PropTypes.func,
|
||||
|
|
@ -201,7 +202,15 @@ export default class PostBody extends PureComponent {
|
|||
};
|
||||
|
||||
openLongPost = preventDoubleTap(() => {
|
||||
const {managedConfig, navigator, onAddReaction, onPermalinkPress, postId} = this.props;
|
||||
const {
|
||||
managedConfig,
|
||||
navigator,
|
||||
onAddReaction,
|
||||
onHashtagPress,
|
||||
onPermalinkPress,
|
||||
postId,
|
||||
} = this.props;
|
||||
|
||||
const options = {
|
||||
screen: 'LongPost',
|
||||
animationType: 'none',
|
||||
|
|
@ -216,6 +225,7 @@ export default class PostBody extends PureComponent {
|
|||
postId,
|
||||
managedConfig,
|
||||
onAddReaction,
|
||||
onHashtagPress,
|
||||
onPermalinkPress,
|
||||
},
|
||||
};
|
||||
|
|
@ -235,7 +245,7 @@ export default class PostBody extends PureComponent {
|
|||
};
|
||||
|
||||
renderAddChannelMember = (style, messageStyle, textStyles) => {
|
||||
const {onPermalinkPress, onPress, postProps} = this.props;
|
||||
const {onPress, postProps} = this.props;
|
||||
|
||||
if (!PostAddChannelMember) {
|
||||
PostAddChannelMember = require('app/components/post_add_channel_member').default;
|
||||
|
|
@ -248,7 +258,6 @@ export default class PostBody extends PureComponent {
|
|||
baseTextStyle={messageStyle}
|
||||
navigator={navigator}
|
||||
onLongPress={this.showOptionsContext}
|
||||
onPermalinkPress={onPermalinkPress}
|
||||
onPostPress={onPress}
|
||||
textStyles={textStyles}
|
||||
postId={postProps.add_channel_member.post_id}
|
||||
|
|
@ -296,7 +305,7 @@ export default class PostBody extends PureComponent {
|
|||
}
|
||||
|
||||
renderPostAdditionalContent = (blockStyles, messageStyle, textStyles) => {
|
||||
const {isReplyPost, message, navigator, onPermalinkPress, postId, postProps} = this.props;
|
||||
const {isReplyPost, message, navigator, onHashtagPress, onPermalinkPress, postId, postProps} = this.props;
|
||||
|
||||
if (!PostBodyAdditionalContent) {
|
||||
PostBodyAdditionalContent = require('app/components/post_body_additional_content').default;
|
||||
|
|
@ -311,8 +320,9 @@ export default class PostBody extends PureComponent {
|
|||
postId={postId}
|
||||
postProps={postProps}
|
||||
textStyles={textStyles}
|
||||
onLongPress={this.showOptionsContext}
|
||||
isReplyPost={isReplyPost}
|
||||
onHashtagPress={onHashtagPress}
|
||||
onLongPress={this.showOptionsContext}
|
||||
onPermalinkPress={onPermalinkPress}
|
||||
/>
|
||||
);
|
||||
|
|
@ -352,6 +362,7 @@ export default class PostBody extends PureComponent {
|
|||
message,
|
||||
navigator,
|
||||
onFailedPostPress,
|
||||
onHashtagPress,
|
||||
onPermalinkPress,
|
||||
onPress,
|
||||
postProps,
|
||||
|
|
@ -422,6 +433,7 @@ export default class PostBody extends PureComponent {
|
|||
isReplyPost={isReplyPost}
|
||||
isSearchResult={isSearchResult}
|
||||
navigator={navigator}
|
||||
onHashtagPress={onHashtagPress}
|
||||
onLongPress={this.showOptionsContext}
|
||||
onPermalinkPress={onPermalinkPress}
|
||||
onPostPress={onPress}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ export default class PostBodyAdditionalContent extends PureComponent {
|
|||
link: PropTypes.string,
|
||||
message: PropTypes.string.isRequired,
|
||||
navigator: PropTypes.object.isRequired,
|
||||
onHashtagPress: PropTypes.func,
|
||||
onLongPress: PropTypes.func,
|
||||
onPermalinkPress: PropTypes.func,
|
||||
openGraphData: PropTypes.object,
|
||||
|
|
@ -291,6 +292,7 @@ export default class PostBodyAdditionalContent extends PureComponent {
|
|||
baseTextStyle,
|
||||
blockStyles,
|
||||
navigator,
|
||||
onHashtagPress,
|
||||
onPermalinkPress,
|
||||
textStyles,
|
||||
theme,
|
||||
|
|
@ -311,6 +313,7 @@ export default class PostBodyAdditionalContent extends PureComponent {
|
|||
postId={postId}
|
||||
textStyles={textStyles}
|
||||
theme={theme}
|
||||
onHashtagPress={onHashtagPress}
|
||||
onLongPress={this.props.onLongPress}
|
||||
onPermalinkPress={onPermalinkPress}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ export default class PostList extends PureComponent {
|
|||
navigator: PropTypes.object,
|
||||
onContentSizeChange: PropTypes.func,
|
||||
onEndReached: PropTypes.func,
|
||||
onHashtagPress: PropTypes.func,
|
||||
onPermalinkPress: PropTypes.func,
|
||||
onPostPress: PropTypes.func,
|
||||
onRefresh: PropTypes.func,
|
||||
|
|
@ -146,7 +147,11 @@ export default class PostList extends PureComponent {
|
|||
};
|
||||
|
||||
showPermalinkView = (postId) => {
|
||||
const {actions, navigator} = this.props;
|
||||
const {
|
||||
actions,
|
||||
navigator,
|
||||
onHashtagPress,
|
||||
} = this.props;
|
||||
|
||||
actions.selectFocusedPostId(postId);
|
||||
|
||||
|
|
@ -164,6 +169,7 @@ export default class PostList extends PureComponent {
|
|||
passProps: {
|
||||
isPermalink: true,
|
||||
onClose: this.handleClosePermalink,
|
||||
onHashtagPress,
|
||||
onPermalinkPress: this.handlePermalinkPress,
|
||||
},
|
||||
};
|
||||
|
|
@ -314,6 +320,7 @@ export default class PostList extends PureComponent {
|
|||
highlightPostId,
|
||||
isSearchResult,
|
||||
navigator,
|
||||
onHashtagPress,
|
||||
onPostPress,
|
||||
renderReplies,
|
||||
shouldRenderReplyButton,
|
||||
|
|
@ -335,6 +342,7 @@ export default class PostList extends PureComponent {
|
|||
renderReplies={renderReplies}
|
||||
isSearchResult={isSearchResult}
|
||||
shouldRenderReplyButton={shouldRenderReplyButton}
|
||||
onHashtagPress={onHashtagPress}
|
||||
onPermalinkPress={this.handlePermalinkPress}
|
||||
onPress={onPostPress}
|
||||
navigator={navigator}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ export default class LongPost extends PureComponent {
|
|||
managedConfig: PropTypes.object,
|
||||
navigator: PropTypes.object,
|
||||
onAddReaction: PropTypes.func,
|
||||
onHashtagPress: PropTypes.func,
|
||||
onPermalinkPress: PropTypes.func,
|
||||
postId: PropTypes.string.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
|
|
@ -178,6 +179,7 @@ export default class LongPost extends PureComponent {
|
|||
hasReactions,
|
||||
managedConfig,
|
||||
navigator,
|
||||
onHashtagPress,
|
||||
onPermalinkPress,
|
||||
postId,
|
||||
theme,
|
||||
|
|
@ -239,6 +241,7 @@ export default class LongPost extends PureComponent {
|
|||
onPress={this.handlePress}
|
||||
isSearchResult={false}
|
||||
showLongPost={true}
|
||||
onHashtagPress={onHashtagPress}
|
||||
onPermalinkPress={onPermalinkPress}
|
||||
navigator={navigator}
|
||||
managedConfig={managedConfig}
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ export default class Permalink extends PureComponent {
|
|||
myMembers: PropTypes.object.isRequired,
|
||||
navigator: PropTypes.object,
|
||||
onClose: PropTypes.func,
|
||||
onHashtagPress: PropTypes.func,
|
||||
onPermalinkPress: PropTypes.func,
|
||||
onPress: PropTypes.func,
|
||||
postIds: PropTypes.array,
|
||||
|
|
@ -319,6 +320,7 @@ export default class Permalink extends PureComponent {
|
|||
currentUserId,
|
||||
focusedPostId,
|
||||
navigator,
|
||||
onHashtagPress,
|
||||
onPermalinkPress,
|
||||
postIds,
|
||||
theme,
|
||||
|
|
@ -352,6 +354,7 @@ export default class Permalink extends PureComponent {
|
|||
isSearchResult={false}
|
||||
shouldRenderReplyButton={false}
|
||||
renderReplies={true}
|
||||
onHashtagPress={onHashtagPress}
|
||||
onPermalinkPress={onPermalinkPress}
|
||||
onPostPress={this.goToThread}
|
||||
postIds={postIds}
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ export default class Search extends PureComponent {
|
|||
selectPost: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
currentTeamId: PropTypes.string.isRequired,
|
||||
initialValue: PropTypes.string,
|
||||
isLandscape: PropTypes.bool.isRequired,
|
||||
navigator: PropTypes.object,
|
||||
postIds: PropTypes.array,
|
||||
|
|
@ -69,6 +70,7 @@ export default class Search extends PureComponent {
|
|||
};
|
||||
|
||||
static defaultProps = {
|
||||
initialValue: '',
|
||||
postIds: [],
|
||||
recent: [],
|
||||
archivedPostIds: [],
|
||||
|
|
@ -86,7 +88,7 @@ export default class Search extends PureComponent {
|
|||
this.state = {
|
||||
channelName: '',
|
||||
cursorPosition: 0,
|
||||
value: '',
|
||||
value: props.initialValue,
|
||||
managedConfig: {},
|
||||
};
|
||||
}
|
||||
|
|
@ -97,9 +99,14 @@ export default class Search extends PureComponent {
|
|||
|
||||
componentDidMount() {
|
||||
this.setManagedConfig();
|
||||
if (this.refs.searchBar) {
|
||||
|
||||
if (this.props.initialValue) {
|
||||
this.search(this.props.initialValue);
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
this.refs.searchBar.focus();
|
||||
if (this.refs.searchBar) {
|
||||
this.refs.searchBar.focus();
|
||||
}
|
||||
}, 150);
|
||||
}
|
||||
}
|
||||
|
|
@ -117,10 +124,12 @@ export default class Search extends PureComponent {
|
|||
if (shouldScroll) {
|
||||
setTimeout(() => {
|
||||
const modifiersCount = enableDateSuggestion ? 5 : 2;
|
||||
this.refs.list._wrapperListRef.getListRef().scrollToOffset({ //eslint-disable-line no-underscore-dangle
|
||||
animated: true,
|
||||
offset: SECTION_HEIGHT + (modifiersCount * MODIFIER_LABEL_HEIGHT) + (recentLength * RECENT_LABEL_HEIGHT) + ((recentLength + 1) * RECENT_SEPARATOR_HEIGHT),
|
||||
});
|
||||
if (this.refs.list) {
|
||||
this.refs.list._wrapperListRef.getListRef().scrollToOffset({ //eslint-disable-line no-underscore-dangle
|
||||
animated: true,
|
||||
offset: SECTION_HEIGHT + (modifiersCount * MODIFIER_LABEL_HEIGHT) + (recentLength * RECENT_LABEL_HEIGHT) + ((recentLength + 1) * RECENT_SEPARATOR_HEIGHT),
|
||||
});
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
|
|
@ -163,6 +172,20 @@ export default class Search extends PureComponent {
|
|||
navigator.push(options);
|
||||
};
|
||||
|
||||
handleHashtagPress = (hashtag) => {
|
||||
if (this.showingPermalink) {
|
||||
this.props.navigator.dismissModal();
|
||||
this.handleClosePermalink();
|
||||
}
|
||||
|
||||
const terms = '#' + hashtag;
|
||||
|
||||
this.handleTextChanged(terms);
|
||||
this.search(terms, false);
|
||||
|
||||
Keyboard.dismiss();
|
||||
};
|
||||
|
||||
handleClosePermalink = () => {
|
||||
const {actions} = this.props;
|
||||
actions.selectFocusedPostId('');
|
||||
|
|
@ -251,6 +274,7 @@ export default class Search extends PureComponent {
|
|||
passProps: {
|
||||
isPermalink,
|
||||
onClose: this.handleClosePermalink,
|
||||
onHashtagPress: this.handleHashtagPress,
|
||||
onPermalinkPress: this.handlePermalinkPress,
|
||||
},
|
||||
};
|
||||
|
|
@ -360,6 +384,7 @@ export default class Search extends PureComponent {
|
|||
previewPost={this.previewPost}
|
||||
goToThread={this.goToThread}
|
||||
navigator={this.props.navigator}
|
||||
onHashtagPress={this.handleHashtagPress}
|
||||
onPermalinkPress={this.handlePermalinkPress}
|
||||
managedConfig={managedConfig}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ export default class SearchResultPost extends PureComponent {
|
|||
goToThread: PropTypes.func.isRequired,
|
||||
managedConfig: PropTypes.object.isRequired,
|
||||
navigator: PropTypes.object.isRequired,
|
||||
onHashtagPress: PropTypes.func.isRequired,
|
||||
onPermalinkPress: PropTypes.func.isRequired,
|
||||
postId: PropTypes.string.isRequired,
|
||||
previewPost: PropTypes.func.isRequired,
|
||||
|
|
@ -32,6 +33,7 @@ export default class SearchResultPost extends PureComponent {
|
|||
postComponentProps.onReply = this.props.goToThread;
|
||||
postComponentProps.shouldRenderReplyButton = true;
|
||||
postComponentProps.managedConfig = this.props.managedConfig;
|
||||
postComponentProps.onHashtagPress = this.props.onHashtagPress;
|
||||
postComponentProps.onPermalinkPress = this.props.onPermalinkPress;
|
||||
}
|
||||
|
||||
|
|
|
|||
4
package-lock.json
generated
4
package-lock.json
generated
|
|
@ -5325,8 +5325,8 @@
|
|||
}
|
||||
},
|
||||
"commonmark-react-renderer": {
|
||||
"version": "github:mattermost/commonmark-react-renderer#86fa63f898802953842526c2030f3b63c5d1ae7a",
|
||||
"from": "commonmark-react-renderer@github:mattermost/commonmark-react-renderer#86fa63f898802953842526c2030f3b63c5d1ae7a",
|
||||
"version": "github:mattermost/commonmark-react-renderer#b560513b93357ee5fd33489fe311bc65d4658870",
|
||||
"from": "github:mattermost/commonmark-react-renderer#b560513b93357ee5fd33489fe311bc65d4658870",
|
||||
"requires": {
|
||||
"in-publish": "^2.0.0",
|
||||
"lodash.assign": "^4.2.0",
|
||||
|
|
|
|||
Loading…
Reference in a new issue