From 1bc4b8a0a57a4046364f4afbb741f2d4e7d48dcb Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Sat, 20 Apr 2019 21:28:03 +0200 Subject: features/composer/index.js โ†’ ComposeForm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../flavours/glitch/features/composer/index.js | 600 --------------------- 1 file changed, 600 deletions(-) delete mode 100644 app/javascript/flavours/glitch/features/composer/index.js (limited to 'app/javascript/flavours/glitch/features/composer') diff --git a/app/javascript/flavours/glitch/features/composer/index.js b/app/javascript/flavours/glitch/features/composer/index.js deleted file mode 100644 index 9d2e0b3da..000000000 --- a/app/javascript/flavours/glitch/features/composer/index.js +++ /dev/null @@ -1,600 +0,0 @@ -// Package imports. -import PropTypes from 'prop-types'; -import React from 'react'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import { defineMessages } from 'react-intl'; - -const APPROX_HASHTAG_RE = /(?:^|[^\/\)\w])#(\S+)/i; - -// Actions. -import { - cancelReplyCompose, - changeCompose, - changeComposeAdvancedOption, - changeComposeSensitivity, - changeComposeSpoilerText, - changeComposeSpoilerness, - changeComposeVisibility, - changeUploadCompose, - clearComposeSuggestions, - fetchComposeSuggestions, - insertEmojiCompose, - mountCompose, - selectComposeSuggestion, - submitCompose, - undoUploadCompose, - unmountCompose, - uploadCompose, -} from 'flavours/glitch/actions/compose'; -import { - closeModal, - openModal, -} from 'flavours/glitch/actions/modal'; -import { changeLocalSetting } from 'flavours/glitch/actions/local_settings'; -import { addPoll, removePoll } from 'flavours/glitch/actions/compose'; - -// Components. -import ComposerOptions from './options'; -import ComposerPublisher from './publisher'; -import ComposerReply from './reply'; -import ComposerSpoiler from './spoiler'; -import ComposerTextarea from './textarea'; -import ComposerUploadForm from './upload_form'; -import ComposerPollForm from './poll_form'; -import ComposerWarning from './warning'; -import ComposerHashtagWarning from './hashtag_warning'; -import ComposerDirectWarning from './direct_warning'; - -// Utils. -import { countableText } from 'flavours/glitch/util/counter'; -import { me } from 'flavours/glitch/util/initial_state'; -import { isMobile } from 'flavours/glitch/util/is_mobile'; -import { assignHandlers } from 'flavours/glitch/util/react_helpers'; -import { wrap } from 'flavours/glitch/util/redux_helpers'; -import { privacyPreference } from 'flavours/glitch/util/privacy_preference'; - -const messages = defineMessages({ - missingDescriptionMessage: { id: 'confirmations.missing_media_description.message', - defaultMessage: 'At least one media attachment is lacking a description. Consider describing all media attachments for the visually impaired before sending your toot.' }, - missingDescriptionConfirm: { id: 'confirmations.missing_media_description.confirm', - defaultMessage: 'Send anyway' }, -}); - -// State mapping. -function mapStateToProps (state) { - const spoilersAlwaysOn = state.getIn(['local_settings', 'always_show_spoilers_field']); - const inReplyTo = state.getIn(['compose', 'in_reply_to']); - const replyPrivacy = inReplyTo ? state.getIn(['statuses', inReplyTo, 'visibility']) : null; - const sideArmBasePrivacy = state.getIn(['local_settings', 'side_arm']); - const sideArmRestrictedPrivacy = replyPrivacy ? privacyPreference(replyPrivacy, sideArmBasePrivacy) : null; - let sideArmPrivacy = null; - switch (state.getIn(['local_settings', 'side_arm_reply_mode'])) { - case 'copy': - sideArmPrivacy = replyPrivacy; - break; - case 'restrict': - sideArmPrivacy = sideArmRestrictedPrivacy; - break; - } - sideArmPrivacy = sideArmPrivacy || sideArmBasePrivacy; - return { - acceptContentTypes: state.getIn(['media_attachments', 'accept_content_types']).toArray().join(','), - 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']), - isChangingUpload: state.getIn(['compose', 'is_changing_upload']), - isUploading: state.getIn(['compose', 'is_uploading']), - layout: state.getIn(['local_settings', 'layout']), - media: state.getIn(['compose', 'media_attachments']), - preselectDate: state.getIn(['compose', 'preselectDate']), - privacy: state.getIn(['compose', 'privacy']), - progress: state.getIn(['compose', 'progress']), - inReplyTo: inReplyTo ? state.getIn(['statuses', inReplyTo]) : null, - replyAccount: inReplyTo ? state.getIn(['statuses', inReplyTo, 'account']) : null, - replyContent: inReplyTo ? state.getIn(['statuses', inReplyTo, 'contentHtml']) : null, - resetFileKey: state.getIn(['compose', 'resetFileKey']), - sideArm: sideArmPrivacy, - sensitive: state.getIn(['compose', 'sensitive']), - 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, - poll: state.getIn(['compose', 'poll']), - spoilersAlwaysOn: spoilersAlwaysOn, - mediaDescriptionConfirmation: state.getIn(['local_settings', 'confirm_missing_media_description']), - preselectOnReply: state.getIn(['local_settings', 'preselect_on_reply']), - }; -}; - -// Dispatch mapping. -const mapDispatchToProps = (dispatch, { intl }) => ({ - onCancelReply() { - dispatch(cancelReplyCompose()); - }, - onChangeAdvancedOption(option, value) { - dispatch(changeComposeAdvancedOption(option, value)); - }, - onChangeDescription(id, description) { - dispatch(changeUploadCompose(id, { description })); - }, - onChangeSensitivity() { - dispatch(changeComposeSensitivity()); - }, - onChangeSpoilerText(text) { - dispatch(changeComposeSpoilerText(text)); - }, - onChangeSpoilerness() { - dispatch(changeComposeSpoilerness()); - }, - onChangeText(text) { - dispatch(changeCompose(text)); - }, - onChangeVisibility(value) { - dispatch(changeComposeVisibility(value)); - }, - onTogglePoll() { - dispatch((_, getState) => { - if (getState().getIn(['compose', 'poll'])) { - dispatch(removePoll()); - } else { - dispatch(addPoll()); - } - }); - }, - onClearSuggestions() { - dispatch(clearComposeSuggestions()); - }, - onCloseModal() { - dispatch(closeModal()); - }, - onFetchSuggestions(token) { - dispatch(fetchComposeSuggestions(token)); - }, - onInsertEmoji(position, emoji) { - dispatch(insertEmojiCompose(position, emoji)); - }, - onMount() { - dispatch(mountCompose()); - }, - onOpenActionsModal(props) { - dispatch(openModal('ACTIONS', props)); - }, - onOpenDoodleModal() { - dispatch(openModal('DOODLE', { noEsc: true })); - }, - onOpenFocalPointModal(id) { - dispatch(openModal('FOCAL_POINT', { id })); - }, - onSelectSuggestion(position, token, suggestion) { - dispatch(selectComposeSuggestion(position, token, suggestion)); - }, - onMediaDescriptionConfirm(routerHistory) { - dispatch(openModal('CONFIRM', { - message: intl.formatMessage(messages.missingDescriptionMessage), - confirm: intl.formatMessage(messages.missingDescriptionConfirm), - onConfirm: () => dispatch(submitCompose(routerHistory)), - onDoNotAsk: () => dispatch(changeLocalSetting(['confirm_missing_media_description'], false)), - })); - }, - onSubmit(routerHistory) { - dispatch(submitCompose(routerHistory)); - }, - onUndoUpload(id) { - dispatch(undoUploadCompose(id)); - }, - onUnmount() { - dispatch(unmountCompose()); - }, - onUpload(files) { - dispatch(uploadCompose(files)); - }, -}); - -// Handlers. -const handlers = { - - // 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(); - }, - - // Selects a suggestion from the autofill. - handleSelect (tokenStart, token, value) { - const { onSelectSuggestion } = this.props; - if (onSelectSuggestion) { - onSelectSuggestion(tokenStart, token, value); - } - }, - - // Submits the status. - handleSubmit () { - const { textarea: { value }, uploadForm } = this; - const { - onChangeText, - onSubmit, - isSubmitting, - isChangingUpload, - isUploading, - media, - anyMedia, - text, - mediaDescriptionConfirmation, - onMediaDescriptionConfirm, - } = this.props; - - // If something changes inside the textarea, then we update the - // state before submitting. - if (onChangeText && text !== value) { - onChangeText(value); - } - - // Submit disabled: - if (isSubmitting || isUploading || isChangingUpload || (!text.trim().length && !anyMedia)) { - return; - } - - // Submit unless there are media with missing descriptions - if (mediaDescriptionConfirmation && onMediaDescriptionConfirm && media && media.some(item => !item.get('description'))) { - const firstWithoutDescription = media.findIndex(item => !item.get('description')); - if (uploadForm) { - const inputs = uploadForm.querySelectorAll('.composer--upload_form--item input'); - if (inputs.length == media.size && firstWithoutDescription !== -1) { - inputs[firstWithoutDescription].focus(); - } - } - onMediaDescriptionConfirm(this.context.router ? this.context.router.history : null); - } else if (onSubmit) { - onSubmit(this.context.router ? this.context.router.history : null); - } - }, - - // Sets a reference to the upload form. - handleRefUploadForm (uploadFormComponent) { - this.uploadForm = uploadFormComponent; - }, - - // Sets a reference to the textarea. - handleRefTextarea (textareaComponent) { - if (textareaComponent) { - this.textarea = textareaComponent.textarea; - } - }, - - // Sets a reference to the CW field. - handleRefSpoilerText (spoilerComponent) { - if (spoilerComponent) { - this.spoilerText = spoilerComponent.spoilerText; - } - } -}; - -// The component. -class Composer extends React.Component { - - // Constructor. - constructor (props) { - super(props); - assignHandlers(this, handlers); - - // Instance variables. - this.textarea = null; - this.spoilerText = null; - } - - // Tells our state the composer has been mounted. - componentDidMount () { - const { onMount } = this.props; - if (onMount) { - onMount(); - } - } - - // Tells our state the composer has been unmounted. - componentWillUnmount () { - const { onUnmount } = this.props; - if (onUnmount) { - onUnmount(); - } - } - - // This statement does several things: - // - If we're beginning a reply, and, - // - Replying to zero or one users, places the cursor at the end - // of the textbox. - // - Replying to more than one user, selects any usernames past - // the first; this provides a convenient shortcut to drop - // everyone else from the conversation. - componentDidUpdate (prevProps) { - const { - textarea, - spoilerText, - } = this; - const { - focusDate, - caretPosition, - isSubmitting, - preselectDate, - text, - preselectOnReply, - } = this.props; - let selectionEnd, selectionStart; - - // Caret/selection handling. - if (focusDate !== prevProps.focusDate) { - switch (true) { - case preselectDate !== prevProps.preselectDate && preselectOnReply: - selectionStart = text.search(/\s/) + 1; - selectionEnd = text.length; - break; - case !isNaN(caretPosition) && caretPosition !== null: - selectionStart = selectionEnd = caretPosition; - break; - default: - selectionStart = selectionEnd = text.length; - } - if (textarea) { - textarea.setSelectionRange(selectionStart, selectionEnd); - textarea.focus(); - textarea.scrollIntoView(); - } - - // Refocuses the textarea after submitting. - } else if (textarea && prevProps.isSubmitting && !isSubmitting) { - textarea.focus(); - } else if (this.props.spoiler !== prevProps.spoiler) { - if (this.props.spoiler) { - if (spoilerText) { - spoilerText.focus(); - } - } else { - if (textarea) { - textarea.focus(); - } - } - } - } - - render () { - const { - handleChangeSpoiler, - handleEmoji, - handleSecondarySubmit, - handleSelect, - handleSubmit, - handleRefUploadForm, - handleRefTextarea, - handleRefSpoilerText, - } = this.handlers; - const { - acceptContentTypes, - advancedOptions, - amUnlocked, - anyMedia, - intl, - isSubmitting, - isChangingUpload, - isUploading, - layout, - media, - poll, - onCancelReply, - onChangeAdvancedOption, - onChangeDescription, - onChangeSensitivity, - onChangeSpoilerness, - onChangeText, - onChangeVisibility, - onTogglePoll, - onClearSuggestions, - onCloseModal, - onFetchSuggestions, - onOpenActionsModal, - onOpenDoodleModal, - onOpenFocalPointModal, - onUndoUpload, - onUpload, - privacy, - progress, - inReplyTo, - resetFileKey, - sensitive, - showSearch, - sideArm, - spoiler, - spoilerText, - suggestions, - text, - spoilersAlwaysOn, - } = this.props; - - let disabledButton = isSubmitting || isUploading || isChangingUpload || (!text.trim().length && !anyMedia); - - return ( -
- {privacy === 'direct' ? : null} - {privacy === 'private' && amUnlocked ? : null} - {privacy !== 'public' && APPROX_HASHTAG_RE.test(text) ? : null} - {inReplyTo && ( - - )} -
- ); - } - -} - -// Props. -Composer.propTypes = { - intl: PropTypes.object.isRequired, - - // State props. - acceptContentTypes: PropTypes.string, - advancedOptions: ImmutablePropTypes.map, - amUnlocked: PropTypes.bool, - focusDate: PropTypes.instanceOf(Date), - caretPosition: PropTypes.number, - isSubmitting: PropTypes.bool, - isChangingUpload: PropTypes.bool, - isUploading: PropTypes.bool, - layout: PropTypes.string, - media: ImmutablePropTypes.list, - preselectDate: PropTypes.instanceOf(Date), - privacy: PropTypes.string, - progress: PropTypes.number, - inReplyTo: ImmutablePropTypes.map, - resetFileKey: PropTypes.number, - 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. - onCancelReply: PropTypes.func, - onChangeAdvancedOption: PropTypes.func, - onChangeDescription: PropTypes.func, - onChangeSensitivity: PropTypes.func, - onChangeSpoilerText: PropTypes.func, - onChangeSpoilerness: PropTypes.func, - onChangeText: PropTypes.func, - onChangeVisibility: PropTypes.func, - onClearSuggestions: PropTypes.func, - onCloseModal: PropTypes.func, - onFetchSuggestions: PropTypes.func, - onInsertEmoji: PropTypes.func, - onMount: PropTypes.func, - onOpenActionsModal: PropTypes.func, - onOpenDoodleModal: PropTypes.func, - onSelectSuggestion: PropTypes.func, - onSubmit: PropTypes.func, - onUndoUpload: PropTypes.func, - onUnmount: PropTypes.func, - onUpload: PropTypes.func, - onMediaDescriptionConfirm: PropTypes.func, -}; - -Composer.contextTypes = { - router: PropTypes.object, -}; - -// Connecting and export. -export { Composer as WrappedComponent }; -export default wrap(Composer, mapStateToProps, mapDispatchToProps, true); -- cgit From f72af5794da52d22fbb2a77e0fcbc111633fcab2 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Sat, 20 Apr 2019 22:05:09 +0200 Subject: Refactor Compose*Warning โ†’ ContainerWarning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Regression: only one warning at a time --- .../features/compose/components/compose_form.js | 13 ++--- .../glitch/features/compose/components/warning.js | 26 ++++++++++ .../compose/containers/warning_container.js | 44 ++++++++++++++++ .../features/composer/direct_warning/index.js | 55 -------------------- .../features/composer/hashtag_warning/index.js | 49 ------------------ .../glitch/features/composer/warning/index.js | 59 ---------------------- 6 files changed, 75 insertions(+), 171 deletions(-) create mode 100644 app/javascript/flavours/glitch/features/compose/components/warning.js create mode 100644 app/javascript/flavours/glitch/features/compose/containers/warning_container.js delete mode 100644 app/javascript/flavours/glitch/features/composer/direct_warning/index.js delete mode 100644 app/javascript/flavours/glitch/features/composer/hashtag_warning/index.js delete mode 100644 app/javascript/flavours/glitch/features/composer/warning/index.js (limited to 'app/javascript/flavours/glitch/features/composer') diff --git a/app/javascript/flavours/glitch/features/compose/components/compose_form.js b/app/javascript/flavours/glitch/features/compose/components/compose_form.js index 0f9b11fa3..1f37a1da5 100644 --- a/app/javascript/flavours/glitch/features/compose/components/compose_form.js +++ b/app/javascript/flavours/glitch/features/compose/components/compose_form.js @@ -4,8 +4,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import { defineMessages, injectIntl } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; -const APPROX_HASHTAG_RE = /(?:^|[^\/\)\w])#(\S+)/i; - // Components. import ComposerOptions from '../../composer/options'; import ComposerPublisher from '../../composer/publisher'; @@ -14,9 +12,7 @@ import ComposerSpoiler from '../../composer/spoiler'; import ComposerTextarea from '../../composer/textarea'; import ComposerUploadForm from '../../composer/upload_form'; import ComposerPollForm from '../../composer/poll_form'; -import ComposerWarning from '../../composer/warning'; -import ComposerHashtagWarning from '../../composer/hashtag_warning'; -import ComposerDirectWarning from '../../composer/direct_warning'; +import WarningContainer from '../containers/warning_container'; // Utils. import { countableText } from 'flavours/glitch/util/counter'; @@ -321,9 +317,8 @@ class ComposeForm extends ImmutablePureComponent { return (
- {privacy === 'direct' ? : null} - {privacy === 'private' && amUnlocked ? : null} - {privacy !== 'public' && APPROX_HASHTAG_RE.test(text) ? : null} + + {inReplyTo && ( )} +
{ + this.props.onChange(this.props.index, e.target.value); + }; + + handleOptionRemove = () => { + this.props.onRemove(this.props.index); + }; + + render () { + const { isPollMultiple, title, index, intl } = this.props; + + return ( +
  • + + +
    + +
    +
  • + ); + } + +} + +export default +@injectIntl +class PollForm extends ImmutablePureComponent { + + static propTypes = { + options: ImmutablePropTypes.list, + expiresIn: PropTypes.number, + isMultiple: PropTypes.bool, + onChangeOption: PropTypes.func.isRequired, + onAddOption: PropTypes.func.isRequired, + onRemoveOption: PropTypes.func.isRequired, + onChangeSettings: PropTypes.func.isRequired, + intl: PropTypes.object.isRequired, + }; + + handleAddOption = () => { + this.props.onAddOption(''); + }; + + handleSelectDuration = e => { + this.props.onChangeSettings(e.target.value, this.props.isMultiple); + }; + + handleSelectMultiple = e => { + this.props.onChangeSettings(this.props.expiresIn, e.target.value === 'true'); + }; + + render () { + const { options, expiresIn, isMultiple, onChangeOption, onRemoveOption, intl } = this.props; + + if (!options) { + return null; + } + + return ( +
    +
      + {options.map((title, i) =>
    + +
    + + + +
    +
    + ); + } + +} diff --git a/app/javascript/flavours/glitch/features/compose/containers/poll_form_container.js b/app/javascript/flavours/glitch/features/compose/containers/poll_form_container.js new file mode 100644 index 000000000..01df024c8 --- /dev/null +++ b/app/javascript/flavours/glitch/features/compose/containers/poll_form_container.js @@ -0,0 +1,29 @@ +import { connect } from 'react-redux'; +import PollForm from '../components/poll_form'; +import { addPollOption, removePollOption, changePollOption, changePollSettings } from 'flavours/glitch/actions/compose'; + +const mapStateToProps = state => ({ + options: state.getIn(['compose', 'poll', 'options']), + expiresIn: state.getIn(['compose', 'poll', 'expires_in']), + isMultiple: state.getIn(['compose', 'poll', 'multiple']), +}); + +const mapDispatchToProps = dispatch => ({ + onAddOption(title) { + dispatch(addPollOption(title)); + }, + + onRemoveOption(index) { + dispatch(removePollOption(index)); + }, + + onChangeOption(index, title) { + dispatch(changePollOption(index, title)); + }, + + onChangeSettings(expiresIn, isMultiple) { + dispatch(changePollSettings(expiresIn, isMultiple)); + }, +}); + +export default connect(mapStateToProps, mapDispatchToProps)(PollForm); diff --git a/app/javascript/flavours/glitch/features/composer/poll_form/components/poll_form.js b/app/javascript/flavours/glitch/features/composer/poll_form/components/poll_form.js deleted file mode 100644 index 1915b62d5..000000000 --- a/app/javascript/flavours/glitch/features/composer/poll_form/components/poll_form.js +++ /dev/null @@ -1,135 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import ImmutablePureComponent from 'react-immutable-pure-component'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import IconButton from 'flavours/glitch/components/icon_button'; -import Icon from 'flavours/glitch/components/icon'; -import classNames from 'classnames'; -import { pollLimits } from 'flavours/glitch/util/initial_state'; - -const messages = defineMessages({ - option_placeholder: { id: 'compose_form.poll.option_placeholder', defaultMessage: 'Choice {number}' }, - add_option: { id: 'compose_form.poll.add_option', defaultMessage: 'Add a choice' }, - remove_option: { id: 'compose_form.poll.remove_option', defaultMessage: 'Remove this choice' }, - poll_duration: { id: 'compose_form.poll.duration', defaultMessage: 'Poll duration' }, - single_choice: { id: 'compose_form.poll.single_choice', defaultMessage: 'Allow one choice' }, - multiple_choices: { id: 'compose_form.poll.multiple_choices', defaultMessage: 'Allow multiple choices' }, - minutes: { id: 'intervals.full.minutes', defaultMessage: '{number, plural, one {# minute} other {# minutes}}' }, - hours: { id: 'intervals.full.hours', defaultMessage: '{number, plural, one {# hour} other {# hours}}' }, - days: { id: 'intervals.full.days', defaultMessage: '{number, plural, one {# day} other {# days}}' }, -}); - -@injectIntl -class Option extends React.PureComponent { - - static propTypes = { - title: PropTypes.string.isRequired, - index: PropTypes.number.isRequired, - isPollMultiple: PropTypes.bool, - onChange: PropTypes.func.isRequired, - onRemove: PropTypes.func.isRequired, - intl: PropTypes.object.isRequired, - }; - - handleOptionTitleChange = e => { - this.props.onChange(this.props.index, e.target.value); - }; - - handleOptionRemove = () => { - this.props.onRemove(this.props.index); - }; - - render () { - const { isPollMultiple, title, index, intl } = this.props; - - return ( -
  • - - -
    - -
    -
  • - ); - } - -} - -export default -@injectIntl -class PollForm extends ImmutablePureComponent { - - static propTypes = { - options: ImmutablePropTypes.list, - expiresIn: PropTypes.number, - isMultiple: PropTypes.bool, - onChangeOption: PropTypes.func.isRequired, - onAddOption: PropTypes.func.isRequired, - onRemoveOption: PropTypes.func.isRequired, - onChangeSettings: PropTypes.func.isRequired, - intl: PropTypes.object.isRequired, - }; - - handleAddOption = () => { - this.props.onAddOption(''); - }; - - handleSelectDuration = e => { - this.props.onChangeSettings(e.target.value, this.props.isMultiple); - }; - - handleSelectMultiple = e => { - this.props.onChangeSettings(this.props.expiresIn, e.target.value === 'true'); - }; - - render () { - const { options, expiresIn, isMultiple, onChangeOption, onRemoveOption, intl } = this.props; - - if (!options) { - return null; - } - - return ( -
    -
      - {options.map((title, i) =>
    - -
    - - - -
    -
    - ); - } - -} diff --git a/app/javascript/flavours/glitch/features/composer/poll_form/index.js b/app/javascript/flavours/glitch/features/composer/poll_form/index.js deleted file mode 100644 index 5232c3b31..000000000 --- a/app/javascript/flavours/glitch/features/composer/poll_form/index.js +++ /dev/null @@ -1,29 +0,0 @@ -import { connect } from 'react-redux'; -import PollForm from './components/poll_form'; -import { addPollOption, removePollOption, changePollOption, changePollSettings } from '../../../actions/compose'; - -const mapStateToProps = state => ({ - options: state.getIn(['compose', 'poll', 'options']), - expiresIn: state.getIn(['compose', 'poll', 'expires_in']), - isMultiple: state.getIn(['compose', 'poll', 'multiple']), -}); - -const mapDispatchToProps = dispatch => ({ - onAddOption(title) { - dispatch(addPollOption(title)); - }, - - onRemoveOption(index) { - dispatch(removePollOption(index)); - }, - - onChangeOption(index, title) { - dispatch(changePollOption(index, title)); - }, - - onChangeSettings(expiresIn, isMultiple) { - dispatch(changePollSettings(expiresIn, isMultiple)); - }, -}); - -export default connect(mapStateToProps, mapDispatchToProps)(PollForm); -- cgit From a243567a3e6100d65477162308e2c1bb5e056c21 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Sun, 21 Apr 2019 12:09:52 +0200 Subject: ComposerUploadForm โ†’ UploadForm + UploadFormContainer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../features/compose/components/compose_form.js | 28 +-- .../glitch/features/compose/components/upload.js | 131 +++++++++++++ .../features/compose/components/upload_form.js | 28 +++ .../features/compose/components/upload_progress.js | 42 +++++ .../compose/containers/compose_form_container.js | 12 -- .../compose/containers/upload_container.js | 31 ++++ .../compose/containers/upload_form_container.js | 8 + .../containers/upload_progress_container.js | 9 + .../glitch/features/composer/upload_form/index.js | 60 ------ .../features/composer/upload_form/item/index.js | 202 --------------------- .../composer/upload_form/progress/index.js | 52 ------ 11 files changed, 251 insertions(+), 352 deletions(-) create mode 100644 app/javascript/flavours/glitch/features/compose/components/upload.js create mode 100644 app/javascript/flavours/glitch/features/compose/components/upload_form.js create mode 100644 app/javascript/flavours/glitch/features/compose/components/upload_progress.js create mode 100644 app/javascript/flavours/glitch/features/compose/containers/upload_container.js create mode 100644 app/javascript/flavours/glitch/features/compose/containers/upload_form_container.js create mode 100644 app/javascript/flavours/glitch/features/compose/containers/upload_progress_container.js delete mode 100644 app/javascript/flavours/glitch/features/composer/upload_form/index.js delete mode 100644 app/javascript/flavours/glitch/features/composer/upload_form/item/index.js delete mode 100644 app/javascript/flavours/glitch/features/composer/upload_form/progress/index.js (limited to 'app/javascript/flavours/glitch/features/composer') diff --git a/app/javascript/flavours/glitch/features/compose/components/compose_form.js b/app/javascript/flavours/glitch/features/compose/components/compose_form.js index ccbcba571..ecd1aed69 100644 --- a/app/javascript/flavours/glitch/features/compose/components/compose_form.js +++ b/app/javascript/flavours/glitch/features/compose/components/compose_form.js @@ -8,7 +8,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component'; import ComposerOptions from '../../composer/options'; import ComposerPublisher from '../../composer/publisher'; import ComposerTextarea from '../../composer/textarea'; -import ComposerUploadForm from '../../composer/upload_form'; +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'; @@ -48,7 +48,6 @@ class ComposeForm extends ImmutablePureComponent { media: ImmutablePropTypes.list, preselectDate: PropTypes.instanceOf(Date), privacy: PropTypes.string, - progress: PropTypes.number, resetFileKey: PropTypes.number, sideArm: PropTypes.string, sensitive: PropTypes.bool, @@ -65,7 +64,6 @@ class ComposeForm extends ImmutablePureComponent { // Dispatch props. onChangeAdvancedOption: PropTypes.func, - onChangeDescription: PropTypes.func, onChangeSensitivity: PropTypes.func, onChangeSpoilerText: PropTypes.func, onChangeSpoilerness: PropTypes.func, @@ -80,7 +78,6 @@ class ComposeForm extends ImmutablePureComponent { onOpenDoodleModal: PropTypes.func, onSelectSuggestion: PropTypes.func, onSubmit: PropTypes.func, - onUndoUpload: PropTypes.func, onUnmount: PropTypes.func, onUpload: PropTypes.func, onMediaDescriptionConfirm: PropTypes.func, @@ -185,11 +182,6 @@ class ComposeForm extends ImmutablePureComponent { } } - // Sets a reference to the upload form. - handleRefUploadForm = (uploadFormComponent) => { - this.uploadForm = uploadFormComponent; - } - // Sets a reference to the textarea. handleRefTextarea = (textareaComponent) => { if (textareaComponent) { @@ -283,7 +275,6 @@ class ComposeForm extends ImmutablePureComponent { handleSecondarySubmit, handleSelect, handleSubmit, - handleRefUploadForm, handleRefTextarea, } = this; const { @@ -299,7 +290,6 @@ class ComposeForm extends ImmutablePureComponent { media, poll, onChangeAdvancedOption, - onChangeDescription, onChangeSensitivity, onChangeSpoilerness, onChangeText, @@ -310,11 +300,8 @@ class ComposeForm extends ImmutablePureComponent { onFetchSuggestions, onOpenActionsModal, onOpenDoodleModal, - onOpenFocalPointModal, - onUndoUpload, onUpload, privacy, - progress, resetFileKey, sensitive, showSearch, @@ -370,18 +357,7 @@ class ComposeForm extends ImmutablePureComponent { value={text} />
    - {isUploading || media && media.size ? ( - - ) : null} +
    { + if (e.keyCode === 13 && (e.ctrlKey || e.metaKey)) { + this.handleSubmit(); + } + } + + handleSubmit = () => { + this.handleInputBlur(); + this.props.onSubmit(this.context.router.history); + } + + handleUndoClick = e => { + e.stopPropagation(); + this.props.onUndo(this.props.media.get('id')); + } + + handleFocalPointClick = e => { + e.stopPropagation(); + this.props.onOpenFocalPoint(this.props.media.get('id')); + } + + handleInputChange = e => { + this.setState({ dirtyDescription: e.target.value }); + } + + handleMouseEnter = () => { + this.setState({ hovered: true }); + } + + handleMouseLeave = () => { + this.setState({ hovered: false }); + } + + handleInputFocus = () => { + this.setState({ focused: true }); + } + + handleClick = () => { + this.setState({ focused: true }); + } + + handleInputBlur = () => { + const { dirtyDescription } = this.state; + + this.setState({ focused: false, dirtyDescription: null }); + + if (dirtyDescription !== null) { + this.props.onDescriptionChange(this.props.media.get('id'), dirtyDescription); + } + } + + render () { + const { intl, media } = this.props; + const active = this.state.hovered || this.state.focused || isUserTouching(); + const description = this.state.dirtyDescription || (this.state.dirtyDescription !== '' && media.get('description')) || ''; + const computedClass = classNames('composer--upload_form--item', { active }); + const focusX = media.getIn(['meta', 'focus', 'x']); + const focusY = media.getIn(['meta', 'focus', 'y']); + const x = ((focusX / 2) + .5) * 100; + const y = ((focusY / -2) + .5) * 100; + + return ( +
    + + {({ scale }) => ( +
    +
    + + {media.get('type') === 'image' && } +
    + +
    +