diff options
author | Reverite <github@reverite.sh> | 2019-05-06 18:17:05 -0700 |
---|---|---|
committer | Reverite <github@reverite.sh> | 2019-05-06 18:17:05 -0700 |
commit | 5b85256b334b13fad26a2bc073a874750a3cdc2e (patch) | |
tree | 2d523aa8266e42ae31ab82c7fc2533cf4a90ff0d /app/javascript/flavours/glitch/features/compose/components/poll_form.js | |
parent | e10a9794f4ed7c90e3190f285359f55dd00da435 (diff) | |
parent | 89d2859296bc5a57a8db07be86239cc938a3f691 (diff) |
Merge remote-tracking branch 'glitch/master' into production
Diffstat (limited to 'app/javascript/flavours/glitch/features/compose/components/poll_form.js')
-rw-r--r-- | app/javascript/flavours/glitch/features/compose/components/poll_form.js | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/app/javascript/flavours/glitch/features/compose/components/poll_form.js b/app/javascript/flavours/glitch/features/compose/components/poll_form.js new file mode 100644 index 000000000..21b5d3d73 --- /dev/null +++ b/app/javascript/flavours/glitch/features/compose/components/poll_form.js @@ -0,0 +1,160 @@ +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 AutosuggestInput from 'flavours/glitch/components/autosuggest_input'; +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, + suggestions: ImmutablePropTypes.list, + onClearSuggestions: PropTypes.func.isRequired, + onFetchSuggestions: PropTypes.func.isRequired, + onSuggestionSelected: 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); + }; + + onSuggestionsClearRequested = () => { + this.props.onClearSuggestions(); + } + + onSuggestionsFetchRequested = (token) => { + this.props.onFetchSuggestions(token); + } + + onSuggestionSelected = (tokenStart, token, value) => { + this.props.onSuggestionSelected(tokenStart, token, value, ['poll', 'options', this.props.index]); + } + + render () { + const { isPollMultiple, title, index, intl } = this.props; + + return ( + <li> + <label className='poll__text editable'> + <span className={classNames('poll__input', { checkbox: isPollMultiple })} /> + + <AutosuggestInput + placeholder={intl.formatMessage(messages.option_placeholder, { number: index + 1 })} + maxLength={pollLimits.max_option_chars} + value={title} + onChange={this.handleOptionTitleChange} + suggestions={this.props.suggestions} + onSuggestionsFetchRequested={this.onSuggestionsFetchRequested} + onSuggestionsClearRequested={this.onSuggestionsClearRequested} + onSuggestionSelected={this.onSuggestionSelected} + searchTokens={[':']} + /> + </label> + + <div className='poll__cancel'> + <IconButton disabled={index <= 1} title={intl.formatMessage(messages.remove_option)} icon='times' onClick={this.handleOptionRemove} /> + </div> + </li> + ); + } + +} + +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, + suggestions: ImmutablePropTypes.list, + onClearSuggestions: PropTypes.func.isRequired, + onFetchSuggestions: PropTypes.func.isRequired, + onSuggestionSelected: 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, ...other } = this.props; + + if (!options) { + return null; + } + + return ( + <div className='compose-form__poll-wrapper'> + <ul> + {options.map((title, i) => <Option title={title} key={i} index={i} onChange={onChangeOption} onRemove={onRemoveOption} isPollMultiple={isMultiple} {...other} />)} + {options.size < pollLimits.max_options && ( + <label className='poll__text editable'> + <span className={classNames('poll__input')} style={{ opacity: 0 }} /> + <button className='button button-secondary' onClick={this.handleAddOption}><Icon icon='plus' /> <FormattedMessage {...messages.add_option} /></button> + </label> + )} + </ul> + + <div className='poll__footer'> + <select value={isMultiple ? 'true' : 'false'} onChange={this.handleSelectMultiple}> + <option value='false'>{intl.formatMessage(messages.single_choice)}</option> + <option value='true'>{intl.formatMessage(messages.multiple_choices)}</option> + </select> + + <select value={expiresIn} onChange={this.handleSelectDuration}> + <option value={300}>{intl.formatMessage(messages.minutes, { number: 5 })}</option> + <option value={1800}>{intl.formatMessage(messages.minutes, { number: 30 })}</option> + <option value={3600}>{intl.formatMessage(messages.hours, { number: 1 })}</option> + <option value={21600}>{intl.formatMessage(messages.hours, { number: 6 })}</option> + <option value={86400}>{intl.formatMessage(messages.days, { number: 1 })}</option> + <option value={259200}>{intl.formatMessage(messages.days, { number: 3 })}</option> + <option value={604800}>{intl.formatMessage(messages.days, { number: 7 })}</option> + </select> + </div> + </div> + ); + } + +} |