diff options
Diffstat (limited to 'app/javascript/flavours/glitch')
10 files changed, 99 insertions, 6 deletions
diff --git a/app/javascript/flavours/glitch/actions/compose.js b/app/javascript/flavours/glitch/actions/compose.js index f117ce771..2fb97fa17 100644 --- a/app/javascript/flavours/glitch/actions/compose.js +++ b/app/javascript/flavours/glitch/actions/compose.js @@ -46,6 +46,7 @@ export const COMPOSE_SPOILERNESS_CHANGE = 'COMPOSE_SPOILERNESS_CHANGE'; export const COMPOSE_SPOILER_TEXT_CHANGE = 'COMPOSE_SPOILER_TEXT_CHANGE'; export const COMPOSE_VISIBILITY_CHANGE = 'COMPOSE_VISIBILITY_CHANGE'; export const COMPOSE_LISTABILITY_CHANGE = 'COMPOSE_LISTABILITY_CHANGE'; +export const COMPOSE_CONTENT_TYPE_CHANGE = 'COMPOSE_CONTENT_TYPE_CHANGE'; export const COMPOSE_EMOJI_INSERT = 'COMPOSE_EMOJI_INSERT'; @@ -147,6 +148,7 @@ export function submitCompose(routerHistory) { } api(getState).post('/api/v1/statuses', { status, + content_type: getState().getIn(['compose', 'content_type']), in_reply_to_id: getState().getIn(['compose', 'in_reply_to'], null), media_ids: media.map(item => item.get('id')), sensitive: getState().getIn(['compose', 'sensitive']) || (spoilerText.length > 0 && media.size !== 0), @@ -517,6 +519,13 @@ export function changeComposeVisibility(value) { }; }; +export function changeComposeContentType(value) { + return { + type: COMPOSE_CONTENT_TYPE_CHANGE, + value, + }; +}; + export function insertEmojiCompose(position, emoji) { return { type: COMPOSE_EMOJI_INSERT, diff --git a/app/javascript/flavours/glitch/actions/statuses.js b/app/javascript/flavours/glitch/actions/statuses.js index 550fe510f..7e22a7f98 100644 --- a/app/javascript/flavours/glitch/actions/statuses.js +++ b/app/javascript/flavours/glitch/actions/statuses.js @@ -71,11 +71,12 @@ export function fetchStatusFail(id, error, skipLoading) { }; }; -export function redraft(status, raw_text) { +export function redraft(status, raw_text, content_type) { return { type: REDRAFT, status, raw_text, + content_type, }; }; @@ -94,7 +95,7 @@ export function deleteStatus(id, router, withRedraft = false) { dispatch(deleteFromTimelines(id)); if (withRedraft) { - dispatch(redraft(status, response.data.text)); + dispatch(redraft(status, response.data.text, response.data.content_type)); if (!getState().getIn(['compose', 'mounted'])) { router.push('/statuses/new'); diff --git a/app/javascript/flavours/glitch/containers/poll_container.js b/app/javascript/flavours/glitch/containers/poll_container.js index cd7216de7..da93cc905 100644 --- a/app/javascript/flavours/glitch/containers/poll_container.js +++ b/app/javascript/flavours/glitch/containers/poll_container.js @@ -1,5 +1,5 @@ import { connect } from 'react-redux'; -import Poll from 'mastodon/components/poll'; +import Poll from 'flavours/glitch/components/poll'; const mapStateToProps = (state, { pollId }) => ({ poll: state.getIn(['polls', pollId]), diff --git a/app/javascript/flavours/glitch/features/compose/components/options.js b/app/javascript/flavours/glitch/features/compose/components/options.js index ee9730961..0c94f5514 100644 --- a/app/javascript/flavours/glitch/features/compose/components/options.js +++ b/app/javascript/flavours/glitch/features/compose/components/options.js @@ -29,6 +29,10 @@ const messages = defineMessages({ defaultMessage: 'Adjust status privacy', id: 'privacy.change', }, + content_type: { + defaultMessage: 'Content type', + id: 'content-type.change', + }, direct_long: { defaultMessage: 'Post to mentioned users only', id: 'privacy.direct.long', @@ -41,6 +45,10 @@ const messages = defineMessages({ defaultMessage: 'Draw something', id: 'compose.attach.doodle', }, + html: { + defaultMessage: 'HTML', + id: 'compose.content-type.html', + }, local_only_long: { defaultMessage: 'Do not post to other instances', id: 'advanced_options.local-only.long', @@ -49,6 +57,14 @@ const messages = defineMessages({ defaultMessage: 'Local-only', id: 'advanced_options.local-only.short', }, + markdown: { + defaultMessage: 'Markdown', + id: 'compose.content-type.markdown', + }, + plain: { + defaultMessage: 'Plain text', + id: 'compose.content-type.plain', + }, private_long: { defaultMessage: 'Post to followers only', id: 'privacy.private.long', @@ -113,6 +129,7 @@ class ComposerOptions extends ImmutablePureComponent { intl: PropTypes.object.isRequired, onChangeAdvancedOption: PropTypes.func, onChangeVisibility: PropTypes.func, + onChangeContentType: PropTypes.func, onTogglePoll: PropTypes.func, onDoodleOpen: PropTypes.func, onModalClose: PropTypes.func, @@ -120,8 +137,10 @@ class ComposerOptions extends ImmutablePureComponent { onToggleSpoiler: PropTypes.func, onUpload: PropTypes.func, privacy: PropTypes.string, + contentType: PropTypes.string, resetFileKey: PropTypes.number, spoiler: PropTypes.bool, + showContentTypeChoice: PropTypes.bool, }; // Handles file selection. @@ -162,6 +181,7 @@ class ComposerOptions extends ImmutablePureComponent { const { acceptContentTypes, advancedOptions, + contentType, disabled, allowMedia, hasMedia, @@ -169,6 +189,7 @@ class ComposerOptions extends ImmutablePureComponent { hasPoll, intl, onChangeAdvancedOption, + onChangeContentType, onChangeVisibility, onTogglePoll, onModalClose, @@ -177,6 +198,7 @@ class ComposerOptions extends ImmutablePureComponent { privacy, resetFileKey, spoiler, + showContentTypeChoice, } = this.props; // We predefine our privacy items so that we can easily pick the @@ -208,6 +230,24 @@ class ComposerOptions extends ImmutablePureComponent { }, }; + const contentTypeItems = { + plain: { + icon: 'align-left', + name: 'text/plain', + text: <FormattedMessage {...messages.plain} />, + }, + html: { + icon: 'code', + name: 'text/html', + text: <FormattedMessage {...messages.html} />, + }, + markdown: { + icon: 'arrow-circle-down', + name: 'text/markdown', + text: <FormattedMessage {...messages.markdown} />, + }, + }; + // The result. return ( <div className='composer--options'> @@ -272,6 +312,22 @@ class ComposerOptions extends ImmutablePureComponent { title={intl.formatMessage(messages.change_privacy)} value={privacy} /> + {showContentTypeChoice && ( + <Dropdown + disabled={disabled} + icon={(contentTypeItems[contentType.split('/')[1]] || {}).icon} + items={[ + contentTypeItems.plain, + contentTypeItems.html, + contentTypeItems.markdown, + ]} + onChange={onChangeContentType} + onModalClose={onModalClose} + onModalOpen={onModalOpen} + title={intl.formatMessage(messages.content_type)} + value={contentType} + /> + )} {onToggleSpoiler && ( <TextIconButton active={spoiler} diff --git a/app/javascript/flavours/glitch/features/compose/containers/options_container.js b/app/javascript/flavours/glitch/features/compose/containers/options_container.js index 2ac7ab8d8..c8c7ecd43 100644 --- a/app/javascript/flavours/glitch/features/compose/containers/options_container.js +++ b/app/javascript/flavours/glitch/features/compose/containers/options_container.js @@ -2,8 +2,10 @@ import { connect } from 'react-redux'; import Options from '../components/options'; import { changeComposeAdvancedOption, + changeComposeContentType, + addPoll, + removePoll, } from 'flavours/glitch/actions/compose'; -import { addPoll, removePoll } from 'flavours/glitch/actions/compose'; import { closeModal, openModal } from 'flavours/glitch/actions/modal'; function mapStateToProps (state) { @@ -17,6 +19,8 @@ function mapStateToProps (state) { allowMedia: !poll && (media ? media.size < 4 && !media.some(item => item.get('type') === 'video') : true), hasMedia: media && !!media.size, allowPoll: !(media && !!media.size), + showContentTypeChoice: state.getIn(['local_settings', 'show_content_type_choice']), + contentType: state.getIn(['compose', 'content_type']), }; }; @@ -26,6 +30,10 @@ const mapDispatchToProps = (dispatch) => ({ dispatch(changeComposeAdvancedOption(option, value)); }, + onChangeContentType(value) { + dispatch(changeComposeContentType(value)); + }, + onTogglePoll() { dispatch((_, getState) => { if (getState().getIn(['compose', 'poll'])) { diff --git a/app/javascript/flavours/glitch/features/compose/index.js b/app/javascript/flavours/glitch/features/compose/index.js index a7795a04d..e60eedfd9 100644 --- a/app/javascript/flavours/glitch/features/compose/index.js +++ b/app/javascript/flavours/glitch/features/compose/index.js @@ -29,7 +29,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ }, }); -export default @connect(mapStateToProps, mapDispatchToProps) +export default @connect(mapStateToProps) @injectIntl class Compose extends React.PureComponent { static propTypes = { diff --git a/app/javascript/flavours/glitch/features/local_settings/page/index.js b/app/javascript/flavours/glitch/features/local_settings/page/index.js index a13bffa3a..cd2d86713 100644 --- a/app/javascript/flavours/glitch/features/local_settings/page/index.js +++ b/app/javascript/flavours/glitch/features/local_settings/page/index.js @@ -153,6 +153,14 @@ export default class LocalSettingsPage extends React.PureComponent { </LocalSettingsPageItem> <LocalSettingsPageItem settings={settings} + item={['show_content_type_choice']} + id='mastodon-settings--show_content_type_choice' + onChange={onChange} + > + <FormattedMessage id='settings.show_content_type_choice' defaultMessage='Show content-type choice when authoring toots' /> + </LocalSettingsPageItem> + <LocalSettingsPageItem + settings={settings} item={['side_arm']} id='mastodon-settings--side_arm' options={[ diff --git a/app/javascript/flavours/glitch/reducers/compose.js b/app/javascript/flavours/glitch/reducers/compose.js index bc1785a48..c0c2fc547 100644 --- a/app/javascript/flavours/glitch/reducers/compose.js +++ b/app/javascript/flavours/glitch/reducers/compose.js @@ -25,6 +25,7 @@ import { COMPOSE_SPOILERNESS_CHANGE, COMPOSE_SPOILER_TEXT_CHANGE, COMPOSE_VISIBILITY_CHANGE, + COMPOSE_CONTENT_TYPE_CHANGE, COMPOSE_EMOJI_INSERT, COMPOSE_UPLOAD_CHANGE_REQUEST, COMPOSE_UPLOAD_CHANGE_SUCCESS, @@ -44,7 +45,7 @@ import { REDRAFT } from 'flavours/glitch/actions/statuses'; import { Map as ImmutableMap, List as ImmutableList, OrderedSet as ImmutableOrderedSet, fromJS } from 'immutable'; import uuid from 'flavours/glitch/util/uuid'; import { privacyPreference } from 'flavours/glitch/util/privacy_preference'; -import { me } from 'flavours/glitch/util/initial_state'; +import { me, defaultContentType } from 'flavours/glitch/util/initial_state'; import { overwrite } from 'flavours/glitch/util/js_helpers'; import { unescapeHTML } from 'flavours/glitch/util/html'; import { recoverHashtags } from 'flavours/glitch/util/hashtag'; @@ -66,6 +67,7 @@ const initialState = ImmutableMap({ spoiler: false, spoiler_text: '', privacy: null, + content_type: defaultContentType || 'text/plain', text: '', focusDate: null, caretPosition: null, @@ -141,6 +143,7 @@ function apiStatusToTextHashtags (state, status) { function clearAll(state) { return state.withMutations(map => { map.set('text', ''); + if (defaultContentType) map.set('content_type', defaultContentType); map.set('spoiler', false); map.set('spoiler_text', ''); map.set('is_submitting', false); @@ -310,6 +313,10 @@ export default function compose(state = initialState, action) { return state .set('privacy', action.value) .set('idempotencyKey', uuid()); + case COMPOSE_CONTENT_TYPE_CHANGE: + return state + .set('content_type', action.value) + .set('idempotencyKey', uuid()); case COMPOSE_CHANGE: return state .set('text', action.text) @@ -348,6 +355,7 @@ export default function compose(state = initialState, action) { case COMPOSE_RESET: return state.withMutations(map => { map.set('in_reply_to', null); + if (defaultContentType) map.set('content_type', defaultContentType); map.set('text', ''); map.set('spoiler', false); map.set('spoiler_text', ''); @@ -427,6 +435,7 @@ export default function compose(state = initialState, action) { case REDRAFT: return state.withMutations(map => { map.set('text', action.raw_text || unescapeHTML(expandMentions(action.status))); + map.set('content_type', action.content_type || 'text/plain'); map.set('in_reply_to', action.status.get('in_reply_to_id')); map.set('privacy', action.status.get('visibility')); map.set('media_attachments', action.status.get('media_attachments')); diff --git a/app/javascript/flavours/glitch/reducers/local_settings.js b/app/javascript/flavours/glitch/reducers/local_settings.js index 8dea4d8f6..5716c5982 100644 --- a/app/javascript/flavours/glitch/reducers/local_settings.js +++ b/app/javascript/flavours/glitch/reducers/local_settings.js @@ -19,6 +19,7 @@ const initialState = ImmutableMap({ preselect_on_reply: true, inline_preview_cards: true, hicolor_privacy_icons: false, + show_content_type_choice: false, content_warnings : ImmutableMap({ auto_unfold : false, filter : null, diff --git a/app/javascript/flavours/glitch/util/initial_state.js b/app/javascript/flavours/glitch/util/initial_state.js index 62588eeaa..99d8a4dbc 100644 --- a/app/javascript/flavours/glitch/util/initial_state.js +++ b/app/javascript/flavours/glitch/util/initial_state.js @@ -27,5 +27,6 @@ export const invitesEnabled = getMeta('invites_enabled'); export const version = getMeta('version'); export const mascot = getMeta('mascot'); export const isStaff = getMeta('is_staff'); +export const defaultContentType = getMeta('default_content_type'); export default initialState; |