Add permalink to timestamp (#5206)
* Add permalink to timestamp * Add permalink to timestamp * Add permalink to timestamp * Add permalink to timestamp * fix error with duplicated import * underline permalink on hover
Этот коммит содержится в:
коммит произвёл
Corey Hulen
родитель
1359f7f391
Коммит
1bbed1cb2b
@@ -376,6 +376,7 @@ export default class PostInfo extends React.Component {
|
|||||||
sameUser={this.props.sameUser}
|
sameUser={this.props.sameUser}
|
||||||
compactDisplay={this.props.compactDisplay}
|
compactDisplay={this.props.compactDisplay}
|
||||||
useMilitaryTime={this.props.useMilitaryTime}
|
useMilitaryTime={this.props.useMilitaryTime}
|
||||||
|
postId={post.id}
|
||||||
/>
|
/>
|
||||||
{flagTrigger}
|
{flagTrigger}
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -6,26 +6,40 @@ import React from 'react';
|
|||||||
import Constants from 'utils/constants.jsx';
|
import Constants from 'utils/constants.jsx';
|
||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||||
|
|
||||||
import {getDateForUnixTicks} from 'utils/utils.jsx';
|
import {getDateForUnixTicks, isMobile, updateWindowDimensions} from 'utils/utils.jsx';
|
||||||
|
|
||||||
|
import {Link} from 'react-router/es6';
|
||||||
|
import TeamStore from 'stores/team_store.jsx';
|
||||||
|
|
||||||
export default class PostTime extends React.Component {
|
export default class PostTime extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);
|
this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);
|
||||||
|
this.state = {
|
||||||
|
currentTeamDisplayName: TeamStore.getCurrent().name,
|
||||||
|
width: '',
|
||||||
|
height: ''
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.intervalId = setInterval(() => {
|
this.intervalId = setInterval(() => {
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
}, Constants.TIME_SINCE_UPDATE_INTERVAL);
|
}, Constants.TIME_SINCE_UPDATE_INTERVAL);
|
||||||
|
window.addEventListener('resize', () => {
|
||||||
|
updateWindowDimensions(this);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
clearInterval(this.intervalId);
|
clearInterval(this.intervalId);
|
||||||
|
window.removeEventListener('resize', () => {
|
||||||
|
updateWindowDimensions(this);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
renderTimeTag() {
|
||||||
return (
|
return (
|
||||||
<time
|
<time
|
||||||
className='post__time'
|
className='post__time'
|
||||||
@@ -35,6 +49,20 @@ export default class PostTime extends React.Component {
|
|||||||
</time>
|
</time>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return isMobile() ?
|
||||||
|
this.renderTimeTag() :
|
||||||
|
(
|
||||||
|
<Link
|
||||||
|
to={`/${this.state.currentTeamDisplayName}/pl/${this.props.postId}`}
|
||||||
|
target='_blank'
|
||||||
|
className='post__permalink'
|
||||||
|
>
|
||||||
|
{this.renderTimeTag()}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PostTime.defaultProps = {
|
PostTime.defaultProps = {
|
||||||
@@ -46,5 +74,6 @@ PostTime.propTypes = {
|
|||||||
eventTime: React.PropTypes.number.isRequired,
|
eventTime: React.PropTypes.number.isRequired,
|
||||||
sameUser: React.PropTypes.bool,
|
sameUser: React.PropTypes.bool,
|
||||||
compactDisplay: React.PropTypes.bool,
|
compactDisplay: React.PropTypes.bool,
|
||||||
useMilitaryTime: React.PropTypes.bool.isRequired
|
useMilitaryTime: React.PropTypes.bool.isRequired,
|
||||||
|
postId: React.PropTypes.string
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import RhsDropdown from 'components/rhs_dropdown.jsx';
|
|||||||
import * as GlobalActions from 'actions/global_actions.jsx';
|
import * as GlobalActions from 'actions/global_actions.jsx';
|
||||||
import {flagPost, unflagPost} from 'actions/post_actions.jsx';
|
import {flagPost, unflagPost} from 'actions/post_actions.jsx';
|
||||||
|
|
||||||
|
import TeamStore from 'stores/team_store.jsx';
|
||||||
|
|
||||||
import * as Utils from 'utils/utils.jsx';
|
import * as Utils from 'utils/utils.jsx';
|
||||||
import * as PostUtils from 'utils/post_utils.jsx';
|
import * as PostUtils from 'utils/post_utils.jsx';
|
||||||
|
|
||||||
@@ -24,6 +26,7 @@ import {FormattedMessage} from 'react-intl';
|
|||||||
import loadingGif from 'images/load.gif';
|
import loadingGif from 'images/load.gif';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import {Link} from 'react-router/es6';
|
||||||
|
|
||||||
export default class RhsComment extends React.Component {
|
export default class RhsComment extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@@ -38,7 +41,23 @@ export default class RhsComment extends React.Component {
|
|||||||
this.canDelete = false;
|
this.canDelete = false;
|
||||||
this.editDisableAction = new DelayedAction(this.handleEditDisable);
|
this.editDisableAction = new DelayedAction(this.handleEditDisable);
|
||||||
|
|
||||||
this.state = {};
|
this.state = {
|
||||||
|
currentTeamDisplayName: TeamStore.getCurrent().name,
|
||||||
|
width: '',
|
||||||
|
height: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
window.addEventListener('resize', () => {
|
||||||
|
Utils.updateWindowDimensions(this);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
window.removeEventListener('resize', () => {
|
||||||
|
Utils.updateWindowDimensions(this);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePermalink(e) {
|
handlePermalink(e) {
|
||||||
@@ -235,6 +254,31 @@ export default class RhsComment extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
timeTag(post, timeOptions) {
|
||||||
|
return (
|
||||||
|
<time
|
||||||
|
className='post__time'
|
||||||
|
dateTime={Utils.getDateForUnixTicks(post.create_at).toISOString()}
|
||||||
|
>
|
||||||
|
{Utils.getDateForUnixTicks(post.create_at).toLocaleString('en', timeOptions)}
|
||||||
|
</time>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTimeTag(post, timeOptions) {
|
||||||
|
return Utils.isMobile() ?
|
||||||
|
this.timeTag(post, timeOptions) :
|
||||||
|
(
|
||||||
|
<Link
|
||||||
|
to={`/${this.state.currentTeamDisplayName}/pl/${post.id}`}
|
||||||
|
target='_blank'
|
||||||
|
className='post__permalink'
|
||||||
|
>
|
||||||
|
{this.timeTag(post, timeOptions)}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const post = this.props.post;
|
const post = this.props.post;
|
||||||
const flagIcon = Constants.FLAG_ICON_SVG;
|
const flagIcon = Constants.FLAG_ICON_SVG;
|
||||||
@@ -479,12 +523,7 @@ export default class RhsComment extends React.Component {
|
|||||||
</li>
|
</li>
|
||||||
{botIndicator}
|
{botIndicator}
|
||||||
<li className='col'>
|
<li className='col'>
|
||||||
<time
|
{this.renderTimeTag(post, timeOptions)}
|
||||||
className='post__time'
|
|
||||||
dateTime={Utils.getDateForUnixTicks(post.create_at).toISOString()}
|
|
||||||
>
|
|
||||||
{Utils.getDateForUnixTicks(post.create_at).toLocaleString('en', timeOptions)}
|
|
||||||
</time>
|
|
||||||
{flagTrigger}
|
{flagTrigger}
|
||||||
</li>
|
</li>
|
||||||
{options}
|
{options}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import RhsDropdown from 'components/rhs_dropdown.jsx';
|
|||||||
|
|
||||||
import ChannelStore from 'stores/channel_store.jsx';
|
import ChannelStore from 'stores/channel_store.jsx';
|
||||||
import UserStore from 'stores/user_store.jsx';
|
import UserStore from 'stores/user_store.jsx';
|
||||||
|
import TeamStore from 'stores/team_store.jsx';
|
||||||
|
|
||||||
import * as GlobalActions from 'actions/global_actions.jsx';
|
import * as GlobalActions from 'actions/global_actions.jsx';
|
||||||
import {flagPost, unflagPost} from 'actions/post_actions.jsx';
|
import {flagPost, unflagPost} from 'actions/post_actions.jsx';
|
||||||
@@ -25,6 +26,7 @@ import {Tooltip, OverlayTrigger} from 'react-bootstrap';
|
|||||||
import {FormattedMessage} from 'react-intl';
|
import {FormattedMessage} from 'react-intl';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import {Link} from 'react-router/es6';
|
||||||
|
|
||||||
export default class RhsRootPost extends React.Component {
|
export default class RhsRootPost extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@@ -38,7 +40,23 @@ export default class RhsRootPost extends React.Component {
|
|||||||
this.canDelete = false;
|
this.canDelete = false;
|
||||||
this.editDisableAction = new DelayedAction(this.handleEditDisable);
|
this.editDisableAction = new DelayedAction(this.handleEditDisable);
|
||||||
|
|
||||||
this.state = {};
|
this.state = {
|
||||||
|
currentTeamDisplayName: TeamStore.getCurrent().name,
|
||||||
|
width: '',
|
||||||
|
height: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
window.addEventListener('resize', () => {
|
||||||
|
Utils.updateWindowDimensions(this);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
window.removeEventListener('resize', () => {
|
||||||
|
Utils.updateWindowDimensions(this);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePermalink(e) {
|
handlePermalink(e) {
|
||||||
@@ -100,6 +118,31 @@ export default class RhsRootPost extends React.Component {
|
|||||||
unflagPost(this.props.post.id);
|
unflagPost(this.props.post.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
timeTag(post, timeOptions) {
|
||||||
|
return (
|
||||||
|
<time
|
||||||
|
className='post__time'
|
||||||
|
dateTime={Utils.getDateForUnixTicks(post.create_at).toISOString()}
|
||||||
|
>
|
||||||
|
{Utils.getDateForUnixTicks(post.create_at).toLocaleString('en', timeOptions)}
|
||||||
|
</time>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTimeTag(post, timeOptions) {
|
||||||
|
return Utils.isMobile() ?
|
||||||
|
this.timeTag(post, timeOptions) :
|
||||||
|
(
|
||||||
|
<Link
|
||||||
|
to={`/${this.state.currentTeamDisplayName}/pl/${post.id}`}
|
||||||
|
target='_blank'
|
||||||
|
className='post__permalink'
|
||||||
|
>
|
||||||
|
{this.timeTag(post, timeOptions)}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const post = this.props.post;
|
const post = this.props.post;
|
||||||
const user = this.props.user;
|
const user = this.props.user;
|
||||||
@@ -426,12 +469,7 @@ export default class RhsRootPost extends React.Component {
|
|||||||
<li className='col__name'>{userProfile}</li>
|
<li className='col__name'>{userProfile}</li>
|
||||||
{botIndicator}
|
{botIndicator}
|
||||||
<li className='col'>
|
<li className='col'>
|
||||||
<time
|
{this.renderTimeTag(post, timeOptions)}
|
||||||
className='post__time'
|
|
||||||
dateTime={Utils.getDateForUnixTicks(post.create_at).toISOString()}
|
|
||||||
>
|
|
||||||
{Utils.getDateForUnixTicks(post.create_at).toLocaleString('en', timeOptions)}
|
|
||||||
</time>
|
|
||||||
<OverlayTrigger
|
<OverlayTrigger
|
||||||
key={'rootpostflagtooltipkey' + flagVisible}
|
key={'rootpostflagtooltipkey' + flagVisible}
|
||||||
delayShow={Constants.OVERLAY_TIME_DELAY}
|
delayShow={Constants.OVERLAY_TIME_DELAY}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ const ActionTypes = Constants.ActionTypes;
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {FormattedMessage, FormattedDate} from 'react-intl';
|
import {FormattedMessage, FormattedDate} from 'react-intl';
|
||||||
import {browserHistory} from 'react-router/es6';
|
import {browserHistory, Link} from 'react-router/es6';
|
||||||
|
|
||||||
export default class SearchResultsItem extends React.Component {
|
export default class SearchResultsItem extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@@ -32,6 +32,24 @@ export default class SearchResultsItem extends React.Component {
|
|||||||
this.shrinkSidebar = this.shrinkSidebar.bind(this);
|
this.shrinkSidebar = this.shrinkSidebar.bind(this);
|
||||||
this.unflagPost = this.unflagPost.bind(this);
|
this.unflagPost = this.unflagPost.bind(this);
|
||||||
this.flagPost = this.flagPost.bind(this);
|
this.flagPost = this.flagPost.bind(this);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
currentTeamDisplayName: TeamStore.getCurrent().name,
|
||||||
|
width: '',
|
||||||
|
height: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
window.addEventListener('resize', () => {
|
||||||
|
Utils.updateWindowDimensions(this);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
window.removeEventListener('resize', () => {
|
||||||
|
Utils.updateWindowDimensions(this);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
hideSidebar() {
|
hideSidebar() {
|
||||||
@@ -59,6 +77,33 @@ export default class SearchResultsItem extends React.Component {
|
|||||||
unflagPost(this.props.post.id);
|
unflagPost(this.props.post.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
timeTag(post) {
|
||||||
|
return (
|
||||||
|
<time className='search-item-time'>
|
||||||
|
<FormattedDate
|
||||||
|
value={post.create_at}
|
||||||
|
hour12={!this.props.useMilitaryTime}
|
||||||
|
hour='2-digit'
|
||||||
|
minute='2-digit'
|
||||||
|
/>
|
||||||
|
</time>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTimeTag(post) {
|
||||||
|
return Utils.isMobile() ?
|
||||||
|
this.timeTag(post) :
|
||||||
|
(
|
||||||
|
<Link
|
||||||
|
to={`/${this.state.currentTeamDisplayName}/pl/${post.id}`}
|
||||||
|
target='_blank'
|
||||||
|
className='post__permalink'
|
||||||
|
>
|
||||||
|
{this.timeTag(post)}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let channelName = null;
|
let channelName = null;
|
||||||
const channel = this.props.channel;
|
const channel = this.props.channel;
|
||||||
@@ -276,14 +321,7 @@ export default class SearchResultsItem extends React.Component {
|
|||||||
</strong></li>
|
</strong></li>
|
||||||
{botIndicator}
|
{botIndicator}
|
||||||
<li className='col'>
|
<li className='col'>
|
||||||
<time className='search-item-time'>
|
{this.renderTimeTag(post)}
|
||||||
<FormattedDate
|
|
||||||
value={post.create_at}
|
|
||||||
hour12={!this.props.useMilitaryTime}
|
|
||||||
hour='2-digit'
|
|
||||||
minute='2-digit'
|
|
||||||
/>
|
|
||||||
</time>
|
|
||||||
{flagContent}
|
{flagContent}
|
||||||
</li>
|
</li>
|
||||||
{rhsControls}
|
{rhsControls}
|
||||||
|
|||||||
@@ -1199,6 +1199,19 @@
|
|||||||
font-size: .9em;
|
font-size: .9em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.post__permalink {
|
||||||
|
color: #333;
|
||||||
|
&:hover, &:focus {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
&:focus {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.post-loading-gif {
|
.post-loading-gif {
|
||||||
height: 10px;
|
height: 10px;
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
|
|||||||
@@ -366,7 +366,9 @@
|
|||||||
text-rendering: auto;
|
text-rendering: auto;
|
||||||
top: -2px;
|
top: -2px;
|
||||||
width: 51px;
|
width: 51px;
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1287,3 +1287,7 @@ export function isEmptyObject(object) {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function updateWindowDimensions(component) {
|
||||||
|
component.setState({width: window.innerWidth, height: window.innerHeight});
|
||||||
|
}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user