import React from 'react';
-import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
+import PropTypes from 'prop-types';
+import ReplyIndicatorContainer from '../containers/reply_indicator_container';
+import AutosuggestTextarea from '../../../components/autosuggest_textarea';
import { defineMessages, injectIntl } from 'react-intl';
+import EmojiPicker from 'flavours/glitch/features/emoji_picker';
+import PollFormContainer from '../containers/poll_form_container';
+import UploadFormContainer from '../containers/upload_form_container';
+import WarningContainer from '../containers/warning_container';
+import { isMobile } from 'flavours/glitch/util/is_mobile';
import ImmutablePureComponent from 'react-immutable-pure-component';
-
-// Components.
+import { countableText } from 'flavours/glitch/util/counter';
import OptionsContainer from '../containers/options_container';
import Publisher from './publisher';
import TextareaIcons from './textarea_icons';
-import UploadFormContainer from '../containers/upload_form_container';
-import PollFormContainer from '../containers/poll_form_container';
-import WarningContainer from '../containers/warning_container';
-import ReplyIndicatorContainer from '../containers/reply_indicator_container';
-import EmojiPicker from 'flavours/glitch/features/emoji_picker';
-import AutosuggestTextarea from '../../../components/autosuggest_textarea';
-
-// Utils.
-import { countableText } from 'flavours/glitch/util/counter';
-import { isMobile } from 'flavours/glitch/util/is_mobile';
const messages = defineMessages({
placeholder: { id: 'compose_form.placeholder', defaultMessage: 'What is on your mind?' },
static propTypes = {
intl: PropTypes.object.isRequired,
-
- // State props.
- advancedOptions: ImmutablePropTypes.map,
- amUnlocked: PropTypes.bool,
+ text: PropTypes.string,
+ suggestions: ImmutablePropTypes.list,
+ spoiler: PropTypes.bool,
+ privacy: PropTypes.string,
+ spoilerText: PropTypes.string,
focusDate: PropTypes.instanceOf(Date),
caretPosition: PropTypes.number,
+ preselectDate: PropTypes.instanceOf(Date),
isSubmitting: PropTypes.bool,
isChangingUpload: PropTypes.bool,
isUploading: PropTypes.bool,
+ onChange: PropTypes.func,
+ onSubmit: PropTypes.func,
+ onClearSuggestions: PropTypes.func,
+ onFetchSuggestions: PropTypes.func,
+ onSuggestionSelected: PropTypes.func,
+ onChangeSpoilerText: PropTypes.func,
+ onPaste: PropTypes.func,
+ onPickEmoji: PropTypes.func,
+ showSearch: PropTypes.bool,
+ anyMedia: PropTypes.bool,
+
+ advancedOptions: ImmutablePropTypes.map,
layout: PropTypes.string,
media: ImmutablePropTypes.list,
- preselectDate: PropTypes.instanceOf(Date),
- privacy: PropTypes.string,
sideArm: PropTypes.string,
sensitive: PropTypes.bool,
- showSearch: PropTypes.bool,
- spoiler: PropTypes.bool,
- spoilerText: PropTypes.string,
- suggestionToken: PropTypes.string,
- suggestions: ImmutablePropTypes.list,
- text: PropTypes.string,
- anyMedia: PropTypes.bool,
spoilersAlwaysOn: PropTypes.bool,
mediaDescriptionConfirmation: PropTypes.bool,
preselectOnReply: PropTypes.bool,
-
- // Dispatch props.
- onChangeSpoilerText: PropTypes.func,
onChangeSpoilerness: PropTypes.func,
- onChangeText: PropTypes.func,
onChangeVisibility: PropTypes.func,
- onClearSuggestions: PropTypes.func,
- onFetchSuggestions: PropTypes.func,
- onInsertEmoji: PropTypes.func,
onMount: PropTypes.func,
- onSelectSuggestion: PropTypes.func,
- onSubmit: PropTypes.func,
onUnmount: PropTypes.func,
- onUpload: PropTypes.func,
+ onPaste: PropTypes.func,
onMediaDescriptionConfirm: PropTypes.func,
};
- // Changes the text value of the spoiler.
- handleChangeSpoiler = ({ target: { value } }) => {
- const { onChangeSpoilerText } = this.props;
- if (onChangeSpoilerText) {
- onChangeSpoilerText(value);
- }
- }
-
- // Inserts an emoji at the caret.
- handleEmoji = (data) => {
- const { textarea: { selectionStart } } = this;
- const { onInsertEmoji } = this.props;
- if (onInsertEmoji) {
- onInsertEmoji(selectionStart, data);
- }
- }
-
- // Handles the secondary submit button.
- handleSecondarySubmit = () => {
- const { handleSubmit } = this.handlers;
- const {
- onChangeVisibility,
- sideArm,
- } = this.props;
- if (sideArm !== 'none' && onChangeVisibility) {
- onChangeVisibility(sideArm);
- }
- handleSubmit();
- }
+ static defaultProps = {
+ showSearch: false,
+ };
- // Selects a suggestion from the autofill.
- handleSelect = (tokenStart, token, value) => {
- const { onSelectSuggestion } = this.props;
- if (onSelectSuggestion) {
- onSelectSuggestion(tokenStart, token, value);
- }
+ handleChange = (e) => {
+ this.props.onChange(e.target.value);
}
handleKeyDown = ({ ctrlKey, keyCode, metaKey, altKey }) => {
}
}
- // When the escape key is released, we focus the UI.
- handleKeyUp = ({ key }) => {
- if (key === 'Escape') {
- document.querySelector('.ui').parentElement.focus();
- }
- }
-
- // Submits the status.
handleSubmit = () => {
const { textarea: { value }, uploadForm } = this;
const {
- onChangeText,
+ onChange,
onSubmit,
isSubmitting,
isChangingUpload,
// If something changes inside the textarea, then we update the
// state before submitting.
- if (onChangeText && text !== value) {
- onChangeText(value);
+ if (onChange && text !== value) {
+ onChange(value);
}
// Submit disabled:
}
}
+ // Changes the text value of the spoiler.
+ handleChangeSpoiler = ({ target: { value } }) => {
+ const { onChangeSpoilerText } = this.props;
+ if (onChangeSpoilerText) {
+ onChangeSpoilerText(value);
+ }
+ }
+
+ // Inserts an emoji at the caret.
+ handleEmoji = (data) => {
+ const { textarea: { selectionStart } } = this;
+ const { onPickEmoji } = this.props;
+ if (onPickEmoji) {
+ onPickEmoji(selectionStart, data);
+ }
+ }
+
+ // Handles the secondary submit button.
+ handleSecondarySubmit = () => {
+ const { handleSubmit } = this.handlers;
+ const {
+ onChangeVisibility,
+ sideArm,
+ } = this.props;
+ if (sideArm !== 'none' && onChangeVisibility) {
+ onChangeVisibility(sideArm);
+ }
+ handleSubmit();
+ }
+
+ // Selects a suggestion from the autofill.
+ onSuggestionSelected = (tokenStart, token, value) => {
+ this.props.onSuggestionSelected(tokenStart, token, value);
+ }
+
+ // When the escape key is released, we focus the UI.
+ handleKeyUp = ({ key }) => {
+ if (key === 'Escape') {
+ document.querySelector('.ui').parentElement.focus();
+ }
+ }
+
// Sets a reference to the textarea.
setAutosuggestTextarea = (textareaComponent) => {
if (textareaComponent) {
}
}
- handleChange = (e) => {
- this.props.onChangeText(e.target.value);
- }
render () {
const {
} = this;
const {
advancedOptions,
- amUnlocked,
anyMedia,
intl,
isSubmitting,
layout,
media,
onChangeSpoilerness,
- onChangeText,
onChangeVisibility,
onClearSuggestions,
onFetchSuggestions,
- onUpload,
+ onPaste,
privacy,
sensitive,
showSearch,
onKeyDown={this.handleKeyDown}
onSuggestionsFetchRequested={onFetchSuggestions}
onSuggestionsClearRequested={onClearSuggestions}
- onSuggestionSelected={this.handleSelect}
- onPaste={onUpload}
+ onSuggestionSelected={this.onSuggestionSelected}
+ onPaste={onPaste}
autoFocus={!showSearch && !isMobile(window.innerWidth, layout)}
/>
disabled={isSubmitting}
onChangeVisibility={onChangeVisibility}
onToggleSpoiler={spoilersAlwaysOn ? null : onChangeSpoilerness}
- onUpload={onUpload}
+ onPaste={onPaste}
privacy={privacy}
sensitive={sensitive || (spoilersAlwaysOn && spoilerText && spoilerText.length > 0)}
spoiler={spoilersAlwaysOn ? (spoilerText && spoilerText.length > 0) : spoiler}
import { connect } from 'react-redux';
+import { defineMessages } from 'react-intl';
import ComposeForm from '../components/compose_form';
import {
changeCompose,
import { changeLocalSetting } from 'flavours/glitch/actions/local_settings';
import { privacyPreference } from 'flavours/glitch/util/privacy_preference';
-import { me } from 'flavours/glitch/util/initial_state';
const messages = defineMessages({
missingDescriptionMessage: { id: 'confirmations.missing_media_description.message',
missingDescriptionConfirm: { id: 'confirmations.missing_media_description.confirm',
defaultMessage: 'Send anyway' },
});
-import { defineMessages } from 'react-intl';
// State mapping.
function mapStateToProps (state) {
sideArmPrivacy = sideArmPrivacy || sideArmBasePrivacy;
return {
advancedOptions: state.getIn(['compose', 'advanced_options']),
- amUnlocked: !state.getIn(['accounts', me, 'locked']),
focusDate: state.getIn(['compose', 'focusDate']),
caretPosition: state.getIn(['compose', 'caretPosition']),
isSubmitting: state.getIn(['compose', 'is_submitting']),
showSearch: state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']),
spoiler: spoilersAlwaysOn || state.getIn(['compose', 'spoiler']),
spoilerText: state.getIn(['compose', 'spoiler_text']),
- suggestionToken: state.getIn(['compose', 'suggestion_token']),
suggestions: state.getIn(['compose', 'suggestions']),
text: state.getIn(['compose', 'text']),
anyMedia: state.getIn(['compose', 'media_attachments']).size > 0,
// Dispatch mapping.
const mapDispatchToProps = (dispatch, { intl }) => ({
- onChangeSpoilerText(text) {
- dispatch(changeComposeSpoilerText(text));
- },
- onChangeSpoilerness() {
- dispatch(changeComposeSpoilerness());
- },
- onChangeText(text) {
+
+ onChange(text) {
dispatch(changeCompose(text));
},
- onChangeVisibility(value) {
- dispatch(changeComposeVisibility(value));
+
+ onSubmit(routerHistory) {
+ dispatch(submitCompose(routerHistory));
},
+
onClearSuggestions() {
dispatch(clearComposeSuggestions());
},
+
onFetchSuggestions(token) {
dispatch(fetchComposeSuggestions(token));
},
- onInsertEmoji(position, emoji) {
+
+ onSuggestionSelected(position, token, suggestion) {
+ dispatch(selectComposeSuggestion(position, token, suggestion));
+ },
+
+ onChangeSpoilerText(text) {
+ dispatch(changeComposeSpoilerText(text));
+ },
+
+ onPaste(files) {
+ dispatch(uploadCompose(files));
+ },
+
+ onPickEmoji(position, emoji) {
dispatch(insertEmojiCompose(position, emoji));
},
+
+ onChangeSpoilerness() {
+ dispatch(changeComposeSpoilerness());
+ },
+
+ onChangeVisibility(value) {
+ dispatch(changeComposeVisibility(value));
+ },
+
onMount() {
dispatch(mountCompose());
},
- onSelectSuggestion(position, token, suggestion) {
- dispatch(selectComposeSuggestion(position, token, suggestion));
+
+ onUnmount() {
+ dispatch(unmountCompose());
},
+
onMediaDescriptionConfirm(routerHistory) {
dispatch(openModal('CONFIRM', {
message: intl.formatMessage(messages.missingDescriptionMessage),
onDoNotAsk: () => dispatch(changeLocalSetting(['confirm_missing_media_description'], false)),
}));
},
- onSubmit(routerHistory) {
- dispatch(submitCompose(routerHistory));
- },
- onUnmount() {
- dispatch(unmountCompose());
- },
- onUpload(files) {
- dispatch(uploadCompose(files));
- },
+
});
export default connect(mapStateToProps, mapDispatchToProps)(ComposeForm);
-// Package imports.
import React from 'react';
-import { connect } from 'react-redux';
+import ComposeFormContainer from './containers/compose_form_container';
+import NavigationContainer from './containers/navigation_container';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
+import { connect } from 'react-redux';
import { injectIntl, defineMessages } from 'react-intl';
import classNames from 'classnames';
-
-// Actions.
-import { cycleElefriendCompose } from 'flavours/glitch/actions/compose';
-
-// Components.
-import ComposeFormContainer from './containers/compose_form_container';
-import HeaderContainer from './containers/header_container';
import SearchContainer from './containers/search_container';
-import SearchResultsContainer from './containers/search_results_container';
-import NavigationContainer from './containers/navigation_container';
+import Motion from 'flavours/glitch/util/optional_motion';
import spring from 'react-motion/lib/spring';
-
-// Utils.
+import SearchResultsContainer from './containers/search_results_container';
import { me, mascot } from 'flavours/glitch/util/initial_state';
-import Motion from 'flavours/glitch/util/optional_motion';
+import { cycleElefriendCompose } from 'flavours/glitch/actions/compose';
+import HeaderContainer from './containers/header_container';
-// Messages.
const messages = defineMessages({
compose: { id: 'navigation_bar.compose', defaultMessage: 'Compose new toot' },
});
-// State mapping.
const mapStateToProps = (state, ownProps) => ({
elefriend: state.getIn(['compose', 'elefriend']),
showSearch: ownProps.multiColumn ? state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']) : ownProps.isSearchPage,
});
-// Dispatch mapping.
const mapDispatchToProps = (dispatch, { intl }) => ({
onClickElefriend () {
dispatch(cycleElefriendCompose());
},
});
-// The component.
export default @connect(mapStateToProps, mapDispatchToProps)
@injectIntl
class Compose extends React.PureComponent {
static propTypes = {
- intl: PropTypes.object.isRequired,
- isSearchPage: PropTypes.bool,
multiColumn: PropTypes.bool,
showSearch: PropTypes.bool,
-
- // State props.
+ isSearchPage: PropTypes.bool,
elefriend: PropTypes.number,
- unreadNotifications: PropTypes.number,
-
- // Dispatch props.
onClickElefriend: PropTypes.func,
+ intl: PropTypes.object.isRequired,
};
- // Rendering.
render () {
const {
elefriend,
} = this.props;
const computedClass = classNames('drawer', `mbstobon-${elefriend}`);
- // The result.
return (
<div className={computedClass} role='region' aria-label={intl.formatMessage(messages.compose)}>
{multiColumn && <HeaderContainer />}