Remove deprecated features at React v15.5 (#1905)
* Remove deprecated features at React v15.5
- [x] React.PropTypes
- [x] react-addons-pure-render-mixin
- [x] react-addons-test-utils
* Uncommented out & Add browserify_rails options
* re-add react-addons-shallow
* Fix syntax error from resolve conflicts
* follow up 59a77923b3
This commit is contained in:
committed by
Eugen
parent
27ea2a88c1
commit
1948f9e767
@ -1,5 +1,5 @@
|
||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import PropTypes from 'prop-types';
|
||||
import Avatar from './avatar';
|
||||
import DisplayName from './display_name';
|
||||
import Permalink from './permalink';
|
||||
@ -19,30 +19,26 @@ const buttonsStyle = {
|
||||
height: '18px'
|
||||
};
|
||||
|
||||
const Account = React.createClass({
|
||||
class Account extends React.PureComponent {
|
||||
|
||||
propTypes: {
|
||||
account: ImmutablePropTypes.map.isRequired,
|
||||
me: React.PropTypes.number.isRequired,
|
||||
onFollow: React.PropTypes.func.isRequired,
|
||||
onBlock: React.PropTypes.func.isRequired,
|
||||
onMute: React.PropTypes.func.isRequired,
|
||||
intl: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
mixins: [PureRenderMixin],
|
||||
constructor (props, context) {
|
||||
super(props, context);
|
||||
this.handleFollow = this.handleFollow.bind(this);
|
||||
this.handleBlock = this.handleBlock.bind(this);
|
||||
this.handleMute = this.handleMute.bind(this);
|
||||
}
|
||||
|
||||
handleFollow () {
|
||||
this.props.onFollow(this.props.account);
|
||||
},
|
||||
}
|
||||
|
||||
handleBlock () {
|
||||
this.props.onBlock(this.props.account);
|
||||
},
|
||||
}
|
||||
|
||||
handleMute () {
|
||||
this.props.onMute(this.props.account);
|
||||
},
|
||||
}
|
||||
|
||||
render () {
|
||||
const { account, me, intl } = this.props;
|
||||
@ -86,6 +82,15 @@ const Account = React.createClass({
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
Account.propTypes = {
|
||||
account: ImmutablePropTypes.map.isRequired,
|
||||
me: PropTypes.number.isRequired,
|
||||
onFollow: PropTypes.func.isRequired,
|
||||
onBlock: PropTypes.func.isRequired,
|
||||
onMute: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
export default injectIntl(Account);
|
||||
|
@ -1,14 +1,8 @@
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||
|
||||
const filename = url => url.split('/').pop().split('#')[0].split('?')[0];
|
||||
|
||||
const AttachmentList = React.createClass({
|
||||
propTypes: {
|
||||
media: ImmutablePropTypes.list.isRequired
|
||||
},
|
||||
|
||||
mixins: [PureRenderMixin],
|
||||
class AttachmentList extends React.PureComponent {
|
||||
|
||||
render () {
|
||||
const { media } = this.props;
|
||||
@ -29,6 +23,10 @@ const AttachmentList = React.createClass({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
AttachmentList.propTypes = {
|
||||
media: ImmutablePropTypes.list.isRequired
|
||||
};
|
||||
|
||||
export default AttachmentList;
|
||||
|
@ -1,5 +1,6 @@
|
||||
import AutosuggestAccountContainer from '../features/compose/containers/autosuggest_account_container';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import PropTypes from 'prop-types';
|
||||
import { isRtl } from '../rtl';
|
||||
|
||||
const textAtCursorMatchesToken = (str, caretPosition) => {
|
||||
@ -27,30 +28,23 @@ const textAtCursorMatchesToken = (str, caretPosition) => {
|
||||
}
|
||||
};
|
||||
|
||||
const AutosuggestTextarea = React.createClass({
|
||||
class AutosuggestTextarea extends React.Component {
|
||||
|
||||
propTypes: {
|
||||
value: React.PropTypes.string,
|
||||
suggestions: ImmutablePropTypes.list,
|
||||
disabled: React.PropTypes.bool,
|
||||
placeholder: React.PropTypes.string,
|
||||
onSuggestionSelected: React.PropTypes.func.isRequired,
|
||||
onSuggestionsClearRequested: React.PropTypes.func.isRequired,
|
||||
onSuggestionsFetchRequested: React.PropTypes.func.isRequired,
|
||||
onChange: React.PropTypes.func.isRequired,
|
||||
onKeyUp: React.PropTypes.func,
|
||||
onKeyDown: React.PropTypes.func,
|
||||
onPaste: React.PropTypes.func.isRequired,
|
||||
},
|
||||
|
||||
getInitialState () {
|
||||
return {
|
||||
constructor (props, context) {
|
||||
super(props, context);
|
||||
this.state = {
|
||||
suggestionsHidden: false,
|
||||
selectedSuggestion: 0,
|
||||
lastToken: null,
|
||||
tokenStart: 0
|
||||
};
|
||||
},
|
||||
this.onChange = this.onChange.bind(this);
|
||||
this.onKeyDown = this.onKeyDown.bind(this);
|
||||
this.onBlur = this.onBlur.bind(this);
|
||||
this.onSuggestionClick = this.onSuggestionClick.bind(this);
|
||||
this.setTextarea = this.setTextarea.bind(this);
|
||||
this.onPaste = this.onPaste.bind(this);
|
||||
}
|
||||
|
||||
onChange (e) {
|
||||
const [ tokenStart, token ] = textAtCursorMatchesToken(e.target.value, e.target.selectionStart);
|
||||
@ -68,7 +62,7 @@ const AutosuggestTextarea = React.createClass({
|
||||
e.target.style.height = `${e.target.scrollHeight}px`;
|
||||
|
||||
this.props.onChange(e);
|
||||
},
|
||||
}
|
||||
|
||||
onKeyDown (e) {
|
||||
const { suggestions, disabled } = this.props;
|
||||
@ -118,7 +112,7 @@ const AutosuggestTextarea = React.createClass({
|
||||
}
|
||||
|
||||
this.props.onKeyDown(e);
|
||||
},
|
||||
}
|
||||
|
||||
onBlur () {
|
||||
// If we hide the suggestions immediately, then this will prevent the
|
||||
@ -128,30 +122,30 @@ const AutosuggestTextarea = React.createClass({
|
||||
setTimeout(() => {
|
||||
this.setState({ suggestionsHidden: true });
|
||||
}, 100);
|
||||
},
|
||||
}
|
||||
|
||||
onSuggestionClick (suggestion, e) {
|
||||
e.preventDefault();
|
||||
this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestion);
|
||||
this.textarea.focus();
|
||||
},
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden) {
|
||||
this.setState({ suggestionsHidden: false });
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
setTextarea (c) {
|
||||
this.textarea = c;
|
||||
},
|
||||
}
|
||||
|
||||
onPaste (e) {
|
||||
if (e.clipboardData && e.clipboardData.files.length === 1) {
|
||||
this.props.onPaste(e.clipboardData.files)
|
||||
e.preventDefault();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
render () {
|
||||
const { value, suggestions, disabled, placeholder, onKeyUp } = this.props;
|
||||
@ -196,6 +190,20 @@ const AutosuggestTextarea = React.createClass({
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
AutosuggestTextarea.propTypes = {
|
||||
value: PropTypes.string,
|
||||
suggestions: ImmutablePropTypes.list,
|
||||
disabled: PropTypes.bool,
|
||||
placeholder: PropTypes.string,
|
||||
onSuggestionSelected: PropTypes.func.isRequired,
|
||||
onSuggestionsClearRequested: PropTypes.func.isRequired,
|
||||
onSuggestionsFetchRequested: PropTypes.func.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onKeyUp: PropTypes.func,
|
||||
onKeyDown: PropTypes.func,
|
||||
onPaste: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default AutosuggestTextarea;
|
||||
|
@ -1,36 +1,23 @@
|
||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const Avatar = React.createClass({
|
||||
class Avatar extends React.PureComponent {
|
||||
|
||||
propTypes: {
|
||||
src: React.PropTypes.string.isRequired,
|
||||
staticSrc: React.PropTypes.string,
|
||||
size: React.PropTypes.number.isRequired,
|
||||
style: React.PropTypes.object,
|
||||
animate: React.PropTypes.bool
|
||||
},
|
||||
|
||||
getDefaultProps () {
|
||||
return {
|
||||
animate: false
|
||||
};
|
||||
},
|
||||
|
||||
getInitialState () {
|
||||
return {
|
||||
constructor (props, context) {
|
||||
super(props, context);
|
||||
this.state = {
|
||||
hovering: false
|
||||
};
|
||||
},
|
||||
|
||||
mixins: [PureRenderMixin],
|
||||
this.handleMouseEnter = this.handleMouseEnter.bind(this);
|
||||
this.handleMouseLeave = this.handleMouseLeave.bind(this);
|
||||
}
|
||||
|
||||
handleMouseEnter () {
|
||||
this.setState({ hovering: true });
|
||||
},
|
||||
}
|
||||
|
||||
handleMouseLeave () {
|
||||
this.setState({ hovering: false });
|
||||
},
|
||||
}
|
||||
|
||||
render () {
|
||||
const { src, size, staticSrc, animate } = this.props;
|
||||
@ -59,6 +46,18 @@ const Avatar = React.createClass({
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
Avatar.propTypes = {
|
||||
src: PropTypes.string.isRequired,
|
||||
staticSrc: PropTypes.string,
|
||||
size: PropTypes.number.isRequired,
|
||||
style: PropTypes.object,
|
||||
animate: PropTypes.bool
|
||||
};
|
||||
|
||||
Avatar.defaultProps = {
|
||||
animate: false
|
||||
};
|
||||
|
||||
export default Avatar;
|
||||
|
@ -1,31 +1,17 @@
|
||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const Button = React.createClass({
|
||||
class Button extends React.PureComponent {
|
||||
|
||||
propTypes: {
|
||||
text: React.PropTypes.node,
|
||||
onClick: React.PropTypes.func,
|
||||
disabled: React.PropTypes.bool,
|
||||
block: React.PropTypes.bool,
|
||||
secondary: React.PropTypes.bool,
|
||||
size: React.PropTypes.number,
|
||||
style: React.PropTypes.object,
|
||||
children: React.PropTypes.node
|
||||
},
|
||||
|
||||
getDefaultProps () {
|
||||
return {
|
||||
size: 36
|
||||
};
|
||||
},
|
||||
|
||||
mixins: [PureRenderMixin],
|
||||
constructor (props, context) {
|
||||
super(props, context);
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
}
|
||||
|
||||
handleClick (e) {
|
||||
if (!this.props.disabled) {
|
||||
this.props.onClick();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
render () {
|
||||
const style = {
|
||||
@ -57,6 +43,21 @@ const Button = React.createClass({
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
Button.propTypes = {
|
||||
text: PropTypes.node,
|
||||
onClick: PropTypes.func,
|
||||
disabled: PropTypes.bool,
|
||||
block: PropTypes.bool,
|
||||
secondary: PropTypes.bool,
|
||||
size: PropTypes.number,
|
||||
style: PropTypes.object,
|
||||
children: PropTypes.node
|
||||
};
|
||||
|
||||
Button.defaultProps = {
|
||||
size: 36
|
||||
};
|
||||
|
||||
export default Button;
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { Motion, spring } from 'react-motion';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const Collapsable = ({ fullHeight, isVisible, children }) => (
|
||||
<Motion defaultStyle={{ opacity: !isVisible ? 0 : 100, height: isVisible ? fullHeight : 0 }} style={{ opacity: spring(!isVisible ? 0 : 100), height: spring(!isVisible ? 0 : fullHeight) }}>
|
||||
@ -11,9 +12,9 @@ const Collapsable = ({ fullHeight, isVisible, children }) => (
|
||||
);
|
||||
|
||||
Collapsable.propTypes = {
|
||||
fullHeight: React.PropTypes.number.isRequired,
|
||||
isVisible: React.PropTypes.bool.isRequired,
|
||||
children: React.PropTypes.node.isRequired
|
||||
fullHeight: PropTypes.number.isRequired,
|
||||
isVisible: PropTypes.bool.isRequired,
|
||||
children: PropTypes.node.isRequired
|
||||
};
|
||||
|
||||
export default Collapsable;
|
||||
|
@ -1,23 +1,22 @@
|
||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const iconStyle = {
|
||||
display: 'inline-block',
|
||||
marginRight: '5px'
|
||||
};
|
||||
|
||||
const ColumnBackButton = React.createClass({
|
||||
class ColumnBackButton extends React.PureComponent {
|
||||
|
||||
contextTypes: {
|
||||
router: React.PropTypes.object
|
||||
},
|
||||
|
||||
mixins: [PureRenderMixin],
|
||||
constructor (props, context) {
|
||||
super(props, context);
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
}
|
||||
|
||||
handleClick () {
|
||||
if (window.history && window.history.length === 1) this.context.router.push("/");
|
||||
else this.context.router.goBack();
|
||||
},
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
@ -28,6 +27,10 @@ const ColumnBackButton = React.createClass({
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
ColumnBackButton.contextTypes = {
|
||||
router: PropTypes.object
|
||||
};
|
||||
|
||||
export default ColumnBackButton;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const outerStyle = {
|
||||
position: 'absolute',
|
||||
@ -16,17 +16,16 @@ const iconStyle = {
|
||||
marginRight: '5px'
|
||||
};
|
||||
|
||||
const ColumnBackButtonSlim = React.createClass({
|
||||
class ColumnBackButtonSlim extends React.PureComponent {
|
||||
|
||||
contextTypes: {
|
||||
router: React.PropTypes.object
|
||||
},
|
||||
|
||||
mixins: [PureRenderMixin],
|
||||
constructor (props, context) {
|
||||
super(props, context);
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
}
|
||||
|
||||
handleClick () {
|
||||
this.context.router.push('/');
|
||||
},
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
@ -39,6 +38,10 @@ const ColumnBackButtonSlim = React.createClass({
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
ColumnBackButtonSlim.contextTypes = {
|
||||
router: PropTypes.object
|
||||
};
|
||||
|
||||
export default ColumnBackButtonSlim;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||
import { Motion, spring } from 'react-motion';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const iconStyle = {
|
||||
fontSize: '16px',
|
||||
@ -11,23 +11,16 @@ const iconStyle = {
|
||||
zIndex: '3'
|
||||
};
|
||||
|
||||
const ColumnCollapsable = React.createClass({
|
||||
class ColumnCollapsable extends React.PureComponent {
|
||||
|
||||
propTypes: {
|
||||
icon: React.PropTypes.string.isRequired,
|
||||
title: React.PropTypes.string,
|
||||
fullHeight: React.PropTypes.number.isRequired,
|
||||
children: React.PropTypes.node,
|
||||
onCollapse: React.PropTypes.func
|
||||
},
|
||||
|
||||
getInitialState () {
|
||||
return {
|
||||
constructor (props, context) {
|
||||
super(props, context);
|
||||
this.state = {
|
||||
collapsed: true
|
||||
};
|
||||
},
|
||||
|
||||
mixins: [PureRenderMixin],
|
||||
this.handleToggleCollapsed = this.handleToggleCollapsed.bind(this);
|
||||
}
|
||||
|
||||
handleToggleCollapsed () {
|
||||
const currentState = this.state.collapsed;
|
||||
@ -37,7 +30,7 @@ const ColumnCollapsable = React.createClass({
|
||||
if (!currentState && this.props.onCollapse) {
|
||||
this.props.onCollapse();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
render () {
|
||||
const { icon, title, fullHeight, children } = this.props;
|
||||
@ -60,6 +53,14 @@ const ColumnCollapsable = React.createClass({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ColumnCollapsable.propTypes = {
|
||||
icon: PropTypes.string.isRequired,
|
||||
title: PropTypes.string,
|
||||
fullHeight: PropTypes.number.isRequired,
|
||||
children: PropTypes.node,
|
||||
onCollapse: PropTypes.func
|
||||
};
|
||||
|
||||
export default ColumnCollapsable;
|
||||
|
@ -1,15 +1,8 @@
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||
import escapeTextContentForBrowser from 'escape-html';
|
||||
import emojify from '../emoji';
|
||||
|
||||
const DisplayName = React.createClass({
|
||||
|
||||
propTypes: {
|
||||
account: ImmutablePropTypes.map.isRequired
|
||||
},
|
||||
|
||||
mixins: [PureRenderMixin],
|
||||
class DisplayName extends React.PureComponent {
|
||||
|
||||
render () {
|
||||
const displayName = this.props.account.get('display_name').length === 0 ? this.props.account.get('username') : this.props.account.get('display_name');
|
||||
@ -22,6 +15,10 @@ const DisplayName = React.createClass({
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
DisplayName.propTypes = {
|
||||
account: ImmutablePropTypes.map.isRequired
|
||||
}
|
||||
|
||||
export default DisplayName;
|
||||
|
@ -1,26 +1,20 @@
|
||||
import Dropdown, { DropdownTrigger, DropdownContent } from 'react-simple-dropdown';
|
||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const DropdownMenu = React.createClass({
|
||||
class DropdownMenu extends React.PureComponent {
|
||||
|
||||
propTypes: {
|
||||
icon: React.PropTypes.string.isRequired,
|
||||
items: React.PropTypes.array.isRequired,
|
||||
size: React.PropTypes.number.isRequired,
|
||||
direction: React.PropTypes.string
|
||||
},
|
||||
|
||||
getDefaultProps () {
|
||||
return {
|
||||
constructor (props, context) {
|
||||
super(props, context);
|
||||
this.state = {
|
||||
direction: 'left'
|
||||
};
|
||||
},
|
||||
|
||||
mixins: [PureRenderMixin],
|
||||
this.setRef = this.setRef.bind(this);
|
||||
this.renderItem = this.renderItem.bind(this);
|
||||
}
|
||||
|
||||
setRef (c) {
|
||||
this.dropdown = c;
|
||||
},
|
||||
}
|
||||
|
||||
handleClick (i, e) {
|
||||
const { action } = this.props.items[i];
|
||||
@ -30,7 +24,7 @@ const DropdownMenu = React.createClass({
|
||||
action();
|
||||
this.dropdown.hide();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
renderItem (item, i) {
|
||||
if (item === null) {
|
||||
@ -46,7 +40,7 @@ const DropdownMenu = React.createClass({
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
render () {
|
||||
const { icon, items, size, direction } = this.props;
|
||||
@ -67,6 +61,13 @@ const DropdownMenu = React.createClass({
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
DropdownMenu.propTypes = {
|
||||
icon: PropTypes.string.isRequired,
|
||||
items: PropTypes.array.isRequired,
|
||||
size: PropTypes.number.isRequired,
|
||||
direction: PropTypes.string
|
||||
};
|
||||
|
||||
export default DropdownMenu;
|
||||
|
@ -1,33 +1,30 @@
|
||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const ExtendedVideoPlayer = React.createClass({
|
||||
class ExtendedVideoPlayer extends React.PureComponent {
|
||||
|
||||
propTypes: {
|
||||
src: React.PropTypes.string.isRequired,
|
||||
time: React.PropTypes.number,
|
||||
controls: React.PropTypes.bool.isRequired,
|
||||
muted: React.PropTypes.bool.isRequired
|
||||
},
|
||||
|
||||
mixins: [PureRenderMixin],
|
||||
constructor (props, context) {
|
||||
super(props, context);
|
||||
this.handleLoadedData = this.handleLoadedData.bind(this);
|
||||
this.setRef = this.setRef.bind(this);
|
||||
}
|
||||
|
||||
handleLoadedData () {
|
||||
if (this.props.time) {
|
||||
this.video.currentTime = this.props.time;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
this.video.addEventListener('loadeddata', this.handleLoadedData);
|
||||
},
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
this.video.removeEventListener('loadeddata', this.handleLoadedData);
|
||||
},
|
||||
}
|
||||
|
||||
setRef (c) {
|
||||
this.video = c;
|
||||
},
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
@ -42,8 +39,15 @@ const ExtendedVideoPlayer = React.createClass({
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
ExtendedVideoPlayer.propTypes = {
|
||||
src: PropTypes.string.isRequired,
|
||||
time: PropTypes.number,
|
||||
controls: PropTypes.bool.isRequired,
|
||||
muted: PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
export default ExtendedVideoPlayer;
|
||||
|
@ -1,33 +1,12 @@
|
||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||
import { Motion, spring } from 'react-motion';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const IconButton = React.createClass({
|
||||
class IconButton extends React.PureComponent {
|
||||
|
||||
propTypes: {
|
||||
title: React.PropTypes.string.isRequired,
|
||||
icon: React.PropTypes.string.isRequired,
|
||||
onClick: React.PropTypes.func,
|
||||
size: React.PropTypes.number,
|
||||
active: React.PropTypes.bool,
|
||||
style: React.PropTypes.object,
|
||||
activeStyle: React.PropTypes.object,
|
||||
disabled: React.PropTypes.bool,
|
||||
inverted: React.PropTypes.bool,
|
||||
animate: React.PropTypes.bool,
|
||||
overlay: React.PropTypes.bool
|
||||
},
|
||||
|
||||
getDefaultProps () {
|
||||
return {
|
||||
size: 18,
|
||||
active: false,
|
||||
disabled: false,
|
||||
animate: false,
|
||||
overlay: false
|
||||
};
|
||||
},
|
||||
|
||||
mixins: [PureRenderMixin],
|
||||
constructor (props, context) {
|
||||
super(props, context);
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
}
|
||||
|
||||
handleClick (e) {
|
||||
e.preventDefault();
|
||||
@ -35,7 +14,7 @@ const IconButton = React.createClass({
|
||||
if (!this.props.disabled) {
|
||||
this.props.onClick(e);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
render () {
|
||||
let style = {
|
||||
@ -84,6 +63,28 @@ const IconButton = React.createClass({
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
IconButton.propTypes = {
|
||||
title: PropTypes.string.isRequired,
|
||||
icon: PropTypes.string.isRequired,
|
||||
onClick: PropTypes.func,
|
||||
size: PropTypes.number,
|
||||
active: PropTypes.bool,
|
||||
style: PropTypes.object,
|
||||
activeStyle: PropTypes.object,
|
||||
disabled: PropTypes.bool,
|
||||
inverted: PropTypes.bool,
|
||||
animate: PropTypes.bool,
|
||||
overlay: PropTypes.bool
|
||||
};
|
||||
|
||||
IconButton.defaultProps = {
|
||||
size: 18,
|
||||
active: false,
|
||||
disabled: false,
|
||||
animate: false,
|
||||
overlay: false
|
||||
};
|
||||
|
||||
export default IconButton;
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const LoadMore = ({ onClick }) => (
|
||||
<a href="#" className='load-more' role='button' onClick={onClick}>
|
||||
@ -7,7 +8,7 @@ const LoadMore = ({ onClick }) => (
|
||||
);
|
||||
|
||||
LoadMore.propTypes = {
|
||||
onClick: React.PropTypes.func
|
||||
onClick: PropTypes.func
|
||||
};
|
||||
|
||||
export default LoadMore;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||
import PropTypes from 'prop-types';
|
||||
import IconButton from './icon_button';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { isIOS } from '../is_mobile';
|
||||
@ -72,17 +72,12 @@ const gifvThumbStyle = {
|
||||
cursor: 'zoom-in'
|
||||
};
|
||||
|
||||
const Item = React.createClass({
|
||||
class Item extends React.PureComponent {
|
||||
|
||||
propTypes: {
|
||||
attachment: ImmutablePropTypes.map.isRequired,
|
||||
index: React.PropTypes.number.isRequired,
|
||||
size: React.PropTypes.number.isRequired,
|
||||
onClick: React.PropTypes.func.isRequired,
|
||||
autoPlayGif: React.PropTypes.bool.isRequired
|
||||
},
|
||||
|
||||
mixins: [PureRenderMixin],
|
||||
constructor (props, context) {
|
||||
super(props, context);
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
}
|
||||
|
||||
handleClick (e) {
|
||||
const { index, onClick } = this.props;
|
||||
@ -93,7 +88,7 @@ const Item = React.createClass({
|
||||
}
|
||||
|
||||
e.stopPropagation();
|
||||
},
|
||||
}
|
||||
|
||||
render () {
|
||||
const { attachment, index, size } = this.props;
|
||||
@ -184,34 +179,34 @@ const Item = React.createClass({
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
const MediaGallery = React.createClass({
|
||||
Item.propTypes = {
|
||||
attachment: ImmutablePropTypes.map.isRequired,
|
||||
index: PropTypes.number.isRequired,
|
||||
size: PropTypes.number.isRequired,
|
||||
onClick: PropTypes.func.isRequired,
|
||||
autoPlayGif: PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
getInitialState () {
|
||||
return {
|
||||
visible: !this.props.sensitive
|
||||
class MediaGallery extends React.PureComponent {
|
||||
|
||||
constructor (props, context) {
|
||||
super(props, context);
|
||||
this.state = {
|
||||
visible: !props.sensitive
|
||||
};
|
||||
},
|
||||
|
||||
propTypes: {
|
||||
sensitive: React.PropTypes.bool,
|
||||
media: ImmutablePropTypes.list.isRequired,
|
||||
height: React.PropTypes.number.isRequired,
|
||||
onOpenMedia: React.PropTypes.func.isRequired,
|
||||
intl: React.PropTypes.object.isRequired,
|
||||
autoPlayGif: React.PropTypes.bool.isRequired
|
||||
},
|
||||
|
||||
mixins: [PureRenderMixin],
|
||||
this.handleOpen = this.handleOpen.bind(this);
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
}
|
||||
|
||||
handleOpen (e) {
|
||||
this.setState({ visible: !this.state.visible });
|
||||
},
|
||||
}
|
||||
|
||||
handleClick (index) {
|
||||
this.props.onOpenMedia(this.props.media, index);
|
||||
},
|
||||
}
|
||||
|
||||
render () {
|
||||
const { media, intl, sensitive } = this.props;
|
||||
@ -249,6 +244,15 @@ const MediaGallery = React.createClass({
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
MediaGallery.propTypes = {
|
||||
sensitive: PropTypes.bool,
|
||||
media: ImmutablePropTypes.list.isRequired,
|
||||
height: PropTypes.number.isRequired,
|
||||
onOpenMedia: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
autoPlayGif: PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(MediaGallery);
|
||||
|
@ -1,21 +1,18 @@
|
||||
const Permalink = React.createClass({
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
contextTypes: {
|
||||
router: React.PropTypes.object
|
||||
},
|
||||
class Permalink extends React.Component {
|
||||
|
||||
propTypes: {
|
||||
href: React.PropTypes.string.isRequired,
|
||||
to: React.PropTypes.string.isRequired,
|
||||
children: React.PropTypes.node
|
||||
},
|
||||
constructor (props, context) {
|
||||
super(props, context);
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
}
|
||||
|
||||
handleClick (e) {
|
||||
if (e.button === 0) {
|
||||
e.preventDefault();
|
||||
this.context.router.push(this.props.to);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
render () {
|
||||
const { href, children, ...other } = this.props;
|
||||
@ -23,6 +20,16 @@ const Permalink = React.createClass({
|
||||
return <a href={href} onClick={this.handleClick} {...other}>{children}</a>;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
Permalink.contextTypes = {
|
||||
router: PropTypes.object
|
||||
};
|
||||
|
||||
Permalink.propTypes = {
|
||||
href: PropTypes.string.isRequired,
|
||||
to: PropTypes.string.isRequired,
|
||||
children: PropTypes.node
|
||||
};
|
||||
|
||||
export default Permalink;
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { injectIntl, FormattedRelative } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const RelativeTimestamp = ({ intl, timestamp }) => {
|
||||
const date = new Date(timestamp);
|
||||
@ -11,8 +12,8 @@ const RelativeTimestamp = ({ intl, timestamp }) => {
|
||||
};
|
||||
|
||||
RelativeTimestamp.propTypes = {
|
||||
intl: React.PropTypes.object.isRequired,
|
||||
timestamp: React.PropTypes.string.isRequired
|
||||
intl: PropTypes.object.isRequired,
|
||||
timestamp: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(RelativeTimestamp);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import PropTypes from 'prop-types';
|
||||
import Avatar from './avatar';
|
||||
import RelativeTimestamp from './relative_timestamp';
|
||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||
import DisplayName from './display_name';
|
||||
import MediaGallery from './media_gallery';
|
||||
import VideoPlayer from './video_player';
|
||||
@ -12,41 +12,25 @@ import { FormattedMessage } from 'react-intl';
|
||||
import emojify from '../emoji';
|
||||
import escapeTextContentForBrowser from 'escape-html';
|
||||
|
||||
const Status = React.createClass({
|
||||
class Status extends React.PureComponent {
|
||||
|
||||
contextTypes: {
|
||||
router: React.PropTypes.object
|
||||
},
|
||||
|
||||
propTypes: {
|
||||
status: ImmutablePropTypes.map,
|
||||
wrapped: React.PropTypes.bool,
|
||||
onReply: React.PropTypes.func,
|
||||
onFavourite: React.PropTypes.func,
|
||||
onReblog: React.PropTypes.func,
|
||||
onDelete: React.PropTypes.func,
|
||||
onOpenMedia: React.PropTypes.func,
|
||||
onOpenVideo: React.PropTypes.func,
|
||||
onBlock: React.PropTypes.func,
|
||||
me: React.PropTypes.number,
|
||||
boostModal: React.PropTypes.bool,
|
||||
autoPlayGif: React.PropTypes.bool,
|
||||
muted: React.PropTypes.bool
|
||||
},
|
||||
|
||||
mixins: [PureRenderMixin],
|
||||
constructor (props, context) {
|
||||
super(props, context);
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
this.handleAccountClick = this.handleAccountClick.bind(this);
|
||||
}
|
||||
|
||||
handleClick () {
|
||||
const { status } = this.props;
|
||||
this.context.router.push(`/statuses/${status.getIn(['reblog', 'id'], status.get('id'))}`);
|
||||
},
|
||||
}
|
||||
|
||||
handleAccountClick (id, e) {
|
||||
if (e.button === 0) {
|
||||
e.preventDefault();
|
||||
this.context.router.push(`/accounts/${id}`);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
render () {
|
||||
let media = '';
|
||||
@ -112,6 +96,26 @@ const Status = React.createClass({
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
Status.contextTypes = {
|
||||
router: PropTypes.object
|
||||
};
|
||||
|
||||
Status.propTypes = {
|
||||
status: ImmutablePropTypes.map,
|
||||
wrapped: PropTypes.bool,
|
||||
onReply: PropTypes.func,
|
||||
onFavourite: PropTypes.func,
|
||||
onReblog: PropTypes.func,
|
||||
onDelete: PropTypes.func,
|
||||
onOpenMedia: PropTypes.func,
|
||||
onOpenVideo: PropTypes.func,
|
||||
onBlock: PropTypes.func,
|
||||
me: PropTypes.number,
|
||||
boostModal: PropTypes.bool,
|
||||
autoPlayGif: PropTypes.bool,
|
||||
muted: PropTypes.bool
|
||||
};
|
||||
|
||||
export default Status;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||
import PropTypes from 'prop-types';
|
||||
import IconButton from './icon_button';
|
||||
import DropdownMenu from './dropdown_menu';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
@ -17,64 +17,57 @@ const messages = defineMessages({
|
||||
report: { id: 'status.report', defaultMessage: 'Report @{name}' }
|
||||
});
|
||||
|
||||
const StatusActionBar = React.createClass({
|
||||
class StatusActionBar extends React.PureComponent {
|
||||
|
||||
contextTypes: {
|
||||
router: React.PropTypes.object
|
||||
},
|
||||
|
||||
propTypes: {
|
||||
status: ImmutablePropTypes.map.isRequired,
|
||||
onReply: React.PropTypes.func,
|
||||
onFavourite: React.PropTypes.func,
|
||||
onReblog: React.PropTypes.func,
|
||||
onDelete: React.PropTypes.func,
|
||||
onMention: React.PropTypes.func,
|
||||
onMute: React.PropTypes.func,
|
||||
onBlock: React.PropTypes.func,
|
||||
onReport: React.PropTypes.func,
|
||||
me: React.PropTypes.number.isRequired,
|
||||
intl: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
mixins: [PureRenderMixin],
|
||||
constructor (props, context) {
|
||||
super(props, context);
|
||||
this.handleReplyClick = this.handleReplyClick.bind(this);
|
||||
this.handleFavouriteClick = this.handleFavouriteClick.bind(this);
|
||||
this.handleReblogClick = this.handleReblogClick.bind(this);
|
||||
this.handleDeleteClick = this.handleDeleteClick.bind(this);
|
||||
this.handleMentionClick = this.handleMentionClick.bind(this);
|
||||
this.handleMuteClick = this.handleMuteClick.bind(this);
|
||||
this.handleBlockClick = this.handleBlockClick.bind(this);
|
||||
this.handleOpen = this.handleOpen.bind(this);
|
||||
this.handleReport = this.handleReport.bind(this);
|
||||
}
|
||||
|
||||
handleReplyClick () {
|
||||
this.props.onReply(this.props.status, this.context.router);
|
||||
},
|
||||
}
|
||||
|
||||
handleFavouriteClick () {
|
||||
this.props.onFavourite(this.props.status);
|
||||
},
|
||||
}
|
||||
|
||||
handleReblogClick (e) {
|
||||
this.props.onReblog(this.props.status, e);
|
||||
},
|
||||
}
|
||||
|
||||
handleDeleteClick () {
|
||||
this.props.onDelete(this.props.status);
|
||||
},
|
||||
}
|
||||
|
||||
handleMentionClick () {
|
||||
this.props.onMention(this.props.status.get('account'), this.context.router);
|
||||
},
|
||||
}
|
||||
|
||||
handleMuteClick () {
|
||||
this.props.onMute(this.props.status.get('account'));
|
||||
},
|
||||
}
|
||||
|
||||
handleBlockClick () {
|
||||
this.props.onBlock(this.props.status.get('account'));
|
||||
},
|
||||
}
|
||||
|
||||
handleOpen () {
|
||||
this.context.router.push(`/statuses/${this.props.status.get('id')}`);
|
||||
},
|
||||
}
|
||||
|
||||
handleReport () {
|
||||
this.props.onReport(this.props.status);
|
||||
this.context.router.push('/report');
|
||||
},
|
||||
}
|
||||
|
||||
render () {
|
||||
const { status, me, intl } = this.props;
|
||||
@ -119,6 +112,24 @@ const StatusActionBar = React.createClass({
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
StatusActionBar.contextTypes = {
|
||||
router: PropTypes.object
|
||||
};
|
||||
|
||||
StatusActionBar.propTypes = {
|
||||
status: ImmutablePropTypes.map.isRequired,
|
||||
onReply: PropTypes.func,
|
||||
onFavourite: PropTypes.func,
|
||||
onReblog: PropTypes.func,
|
||||
onDelete: PropTypes.func,
|
||||
onMention: PropTypes.func,
|
||||
onMute: PropTypes.func,
|
||||
onBlock: PropTypes.func,
|
||||
onReport: PropTypes.func,
|
||||
me: PropTypes.number.isRequired,
|
||||
intl: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(StatusActionBar);
|
||||
|
@ -1,29 +1,24 @@
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||
import escapeTextContentForBrowser from 'escape-html';
|
||||
import PropTypes from 'prop-types';
|
||||
import emojify from '../emoji';
|
||||
import { isRtl } from '../rtl';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import Permalink from './permalink';
|
||||
|
||||
const StatusContent = React.createClass({
|
||||
class StatusContent extends React.PureComponent {
|
||||
|
||||
contextTypes: {
|
||||
router: React.PropTypes.object
|
||||
},
|
||||
|
||||
propTypes: {
|
||||
status: ImmutablePropTypes.map.isRequired,
|
||||
onClick: React.PropTypes.func
|
||||
},
|
||||
|
||||
getInitialState () {
|
||||
return {
|
||||
constructor (props, context) {
|
||||
super(props, context);
|
||||
this.state = {
|
||||
hidden: true
|
||||
};
|
||||
},
|
||||
|
||||
mixins: [PureRenderMixin],
|
||||
this.onMentionClick = this.onMentionClick.bind(this);
|
||||
this.onHashtagClick = this.onHashtagClick.bind(this);
|
||||
this.handleMouseDown = this.handleMouseDown.bind(this)
|
||||
this.handleMouseUp = this.handleMouseUp.bind(this);
|
||||
this.handleSpoilerClick = this.handleSpoilerClick.bind(this);
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
const node = ReactDOM.findDOMNode(this);
|
||||
@ -47,14 +42,14 @@ const StatusContent = React.createClass({
|
||||
link.setAttribute('title', link.href);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
onMentionClick (mention, e) {
|
||||
if (e.button === 0) {
|
||||
e.preventDefault();
|
||||
this.context.router.push(`/accounts/${mention.get('id')}`);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
onHashtagClick (hashtag, e) {
|
||||
hashtag = hashtag.replace(/^#/, '').toLowerCase();
|
||||
@ -63,11 +58,11 @@ const StatusContent = React.createClass({
|
||||
e.preventDefault();
|
||||
this.context.router.push(`/timelines/tag/${hashtag}`);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
handleMouseDown (e) {
|
||||
this.startXY = [e.clientX, e.clientY];
|
||||
},
|
||||
}
|
||||
|
||||
handleMouseUp (e) {
|
||||
const [ startX, startY ] = this.startXY;
|
||||
@ -82,12 +77,12 @@ const StatusContent = React.createClass({
|
||||
}
|
||||
|
||||
this.startXY = null;
|
||||
},
|
||||
}
|
||||
|
||||
handleSpoilerClick (e) {
|
||||
e.preventDefault();
|
||||
this.setState({ hidden: !this.state.hidden });
|
||||
},
|
||||
}
|
||||
|
||||
render () {
|
||||
const { status } = this.props;
|
||||
@ -146,8 +141,17 @@ const StatusContent = React.createClass({
|
||||
/>
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
StatusContent.contextTypes = {
|
||||
router: PropTypes.object
|
||||
};
|
||||
|
||||
StatusContent.propTypes = {
|
||||
status: ImmutablePropTypes.map.isRequired,
|
||||
onClick: PropTypes.func
|
||||
};
|
||||
|
||||
export default StatusContent;
|
||||
|
@ -1,32 +1,18 @@
|
||||
import Status from './status';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||
import { ScrollContainer } from 'react-router-scroll';
|
||||
import PropTypes from 'prop-types';
|
||||
import StatusContainer from '../containers/status_container';
|
||||
import LoadMore from './load_more';
|
||||
|
||||
const StatusList = React.createClass({
|
||||
class StatusList extends React.PureComponent {
|
||||
|
||||
propTypes: {
|
||||
statusIds: ImmutablePropTypes.list.isRequired,
|
||||
onScrollToBottom: React.PropTypes.func,
|
||||
onScrollToTop: React.PropTypes.func,
|
||||
onScroll: React.PropTypes.func,
|
||||
trackScroll: React.PropTypes.bool,
|
||||
isLoading: React.PropTypes.bool,
|
||||
isUnread: React.PropTypes.bool,
|
||||
hasMore: React.PropTypes.bool,
|
||||
prepend: React.PropTypes.node,
|
||||
emptyMessage: React.PropTypes.node
|
||||
},
|
||||
|
||||
getDefaultProps () {
|
||||
return {
|
||||
trackScroll: true
|
||||
};
|
||||
},
|
||||
|
||||
mixins: [PureRenderMixin],
|
||||
constructor (props, context) {
|
||||
super(props, context);
|
||||
this.handleScroll = this.handleScroll.bind(this);
|
||||
this.setRef = this.setRef.bind(this);
|
||||
this.handleLoadMore = this.handleLoadMore.bind(this);
|
||||
}
|
||||
|
||||
handleScroll (e) {
|
||||
const { scrollTop, scrollHeight, clientHeight } = e.target;
|
||||
@ -40,38 +26,38 @@ const StatusList = React.createClass({
|
||||
} else if (this.props.onScroll) {
|
||||
this.props.onScroll();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
this.attachScrollListener();
|
||||
},
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps) {
|
||||
if (this.node.scrollTop > 0 && (prevProps.statusIds.size < this.props.statusIds.size && prevProps.statusIds.first() !== this.props.statusIds.first() && !!this._oldScrollPosition)) {
|
||||
this.node.scrollTop = this.node.scrollHeight - this._oldScrollPosition;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
this.detachScrollListener();
|
||||
},
|
||||
}
|
||||
|
||||
attachScrollListener () {
|
||||
this.node.addEventListener('scroll', this.handleScroll);
|
||||
},
|
||||
}
|
||||
|
||||
detachScrollListener () {
|
||||
this.node.removeEventListener('scroll', this.handleScroll);
|
||||
},
|
||||
}
|
||||
|
||||
setRef (c) {
|
||||
this.node = c;
|
||||
},
|
||||
}
|
||||
|
||||
handleLoadMore (e) {
|
||||
e.preventDefault();
|
||||
this.props.onScrollToBottom();
|
||||
},
|
||||
}
|
||||
|
||||
render () {
|
||||
const { statusIds, onScrollToBottom, trackScroll, isLoading, isUnread, hasMore, prepend, emptyMessage } = this.props;
|
||||
@ -123,6 +109,23 @@ const StatusList = React.createClass({
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
StatusList.propTypes = {
|
||||
statusIds: ImmutablePropTypes.list.isRequired,
|
||||
onScrollToBottom: PropTypes.func,
|
||||
onScrollToTop: PropTypes.func,
|
||||
onScroll: PropTypes.func,
|
||||
trackScroll: PropTypes.bool,
|
||||
isLoading: PropTypes.bool,
|
||||
isUnread: PropTypes.bool,
|
||||
hasMore: PropTypes.bool,
|
||||
prepend: PropTypes.node,
|
||||
emptyMessage: PropTypes.node
|
||||
};
|
||||
|
||||
StatusList.defaultProps = {
|
||||
trackScroll: true
|
||||
};
|
||||
|
||||
export default StatusList;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||
import PropTypes from 'prop-types';
|
||||
import IconButton from './icon_button';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { isIOS } from '../is_mobile';
|
||||
@ -72,39 +72,30 @@ const expandButtonStyle = {
|
||||
zIndex: '100'
|
||||
};
|
||||
|
||||
const VideoPlayer = React.createClass({
|
||||
propTypes: {
|
||||
media: ImmutablePropTypes.map.isRequired,
|
||||
width: React.PropTypes.number,
|
||||
height: React.PropTypes.number,
|
||||
sensitive: React.PropTypes.bool,
|
||||
intl: React.PropTypes.object.isRequired,
|
||||
autoplay: React.PropTypes.bool,
|
||||
onOpenVideo: React.PropTypes.func.isRequired
|
||||
},
|
||||
class VideoPlayer extends React.PureComponent {
|
||||
|
||||
getDefaultProps () {
|
||||
return {
|
||||
width: 239,
|
||||
height: 110
|
||||
};
|
||||
},
|
||||
|
||||
getInitialState () {
|
||||
return {
|
||||
constructor (props, context) {
|
||||
super(props, context);
|
||||
this.state = {
|
||||
visible: !this.props.sensitive,
|
||||
preview: true,
|
||||
muted: true,
|
||||
hasAudio: true,
|
||||
videoError: false
|
||||
};
|
||||
},
|
||||
|
||||
mixins: [PureRenderMixin],
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
this.handleVideoClick = this.handleVideoClick.bind(this);
|
||||
this.handleOpen = this.handleOpen.bind(this);
|
||||
this.handleVisibility = this.handleVisibility.bind(this);
|
||||
this.handleExpand = this.handleExpand.bind(this);
|
||||
this.setRef = this.setRef.bind(this);
|
||||
this.handleLoadedData = this.handleLoadedData.bind(this);
|
||||
this.handleVideoError = this.handleVideoError.bind(this);
|
||||
}
|
||||
|
||||
handleClick () {
|
||||
this.setState({ muted: !this.state.muted });
|
||||
},
|
||||
}
|
||||
|
||||
handleVideoClick (e) {
|
||||
e.stopPropagation();
|
||||
@ -116,37 +107,37 @@ const VideoPlayer = React.createClass({
|
||||
} else {
|
||||
node.pause();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
handleOpen () {
|
||||
this.setState({ preview: !this.state.preview });
|
||||
},
|
||||
}
|
||||
|
||||
handleVisibility () {
|
||||
this.setState({
|
||||
visible: !this.state.visible,
|
||||
preview: true
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
handleExpand () {
|
||||
this.video.pause();
|
||||
this.props.onOpenVideo(this.props.media, this.video.currentTime);
|
||||
},
|
||||
}
|
||||
|
||||
setRef (c) {
|
||||
this.video = c;
|
||||
},
|
||||
}
|
||||
|
||||
handleLoadedData () {
|
||||
if (('WebkitAppearance' in document.documentElement.style && this.video.audioTracks.length === 0) || this.video.mozHasAudio === false) {
|
||||
this.setState({ hasAudio: false });
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
handleVideoError () {
|
||||
this.setState({ videoError: true });
|
||||
},
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
if (!this.video) {
|
||||
@ -155,7 +146,7 @@ const VideoPlayer = React.createClass({
|
||||
|
||||
this.video.addEventListener('loadeddata', this.handleLoadedData);
|
||||
this.video.addEventListener('error', this.handleVideoError);
|
||||
},
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
if (!this.video) {
|
||||
@ -164,7 +155,7 @@ const VideoPlayer = React.createClass({
|
||||
|
||||
this.video.addEventListener('loadeddata', this.handleLoadedData);
|
||||
this.video.addEventListener('error', this.handleVideoError);
|
||||
},
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
if (!this.video) {
|
||||
@ -173,7 +164,7 @@ const VideoPlayer = React.createClass({
|
||||
|
||||
this.video.removeEventListener('loadeddata', this.handleLoadedData);
|
||||
this.video.removeEventListener('error', this.handleVideoError);
|
||||
},
|
||||
}
|
||||
|
||||
render () {
|
||||
const { media, intl, width, height, sensitive, autoplay } = this.props;
|
||||
@ -247,6 +238,21 @@ const VideoPlayer = React.createClass({
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
VideoPlayer.propTypes = {
|
||||
media: ImmutablePropTypes.map.isRequired,
|
||||
width: PropTypes.number,
|
||||
height: PropTypes.number,
|
||||
sensitive: PropTypes.bool,
|
||||
intl: PropTypes.object.isRequired,
|
||||
autoplay: PropTypes.bool,
|
||||
onOpenVideo: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
VideoPlayer.defaultProps = {
|
||||
width: 239,
|
||||
height: 110
|
||||
};
|
||||
|
||||
export default injectIntl(VideoPlayer);
|
||||
|
Reference in New Issue
Block a user