From 130bdb5ee8c0689a44b353be9bc0ca78b75bdf2e Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Fri, 31 Aug 2018 16:41:58 +0200 Subject: [Glitch] Show compose form on delete & redraft when in mobile layout Port 025fbb8285cdedf495d9e4d015db611b0c622cbb to glitch-soc --- .../flavours/glitch/features/status/components/action_bar.js | 4 ++-- app/javascript/flavours/glitch/features/status/index.js | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'app/javascript/flavours/glitch/features/status') diff --git a/app/javascript/flavours/glitch/features/status/components/action_bar.js b/app/javascript/flavours/glitch/features/status/components/action_bar.js index 99e2c594b..413833a79 100644 --- a/app/javascript/flavours/glitch/features/status/components/action_bar.js +++ b/app/javascript/flavours/glitch/features/status/components/action_bar.js @@ -70,11 +70,11 @@ export default class ActionBar extends React.PureComponent { } handleDeleteClick = () => { - this.props.onDelete(this.props.status); + this.props.onDelete(this.props.status, this.context.router.history); } handleRedraftClick = () => { - this.props.onDelete(this.props.status, true); + this.props.onDelete(this.props.status, this.context.router.history, true); } handleDirectClick = () => { diff --git a/app/javascript/flavours/glitch/features/status/index.js b/app/javascript/flavours/glitch/features/status/index.js index ddc2f820a..1fceaa5ea 100644 --- a/app/javascript/flavours/glitch/features/status/index.js +++ b/app/javascript/flavours/glitch/features/status/index.js @@ -159,16 +159,16 @@ export default class Status extends ImmutablePureComponent { } } - handleDeleteClick = (status, withRedraft = false) => { + handleDeleteClick = (status, history, withRedraft = false) => { const { dispatch, intl } = this.props; if (!deleteModal) { - dispatch(deleteStatus(status.get('id'), withRedraft)); + dispatch(deleteStatus(status.get('id'), history, withRedraft)); } else { dispatch(openModal('CONFIRM', { message: intl.formatMessage(withRedraft ? messages.redraftMessage : messages.deleteMessage), confirm: intl.formatMessage(withRedraft ? messages.redraftConfirm : messages.deleteConfirm), - onConfirm: () => dispatch(deleteStatus(status.get('id'), withRedraft)), + onConfirm: () => dispatch(deleteStatus(status.get('id'), history, withRedraft)), })); } } -- cgit From 9d2739d74da26b725f03eb5a19a93c6041714be7 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Tue, 28 Aug 2018 14:10:26 +0200 Subject: Add a setting to automatically unfold all content warnings --- app/javascript/flavours/glitch/components/status.js | 1 + .../glitch/features/local_settings/navigation/index.js | 17 ++++++++++++----- .../glitch/features/local_settings/page/index.js | 13 +++++++++++++ app/javascript/flavours/glitch/features/status/index.js | 4 ++-- .../flavours/glitch/reducers/local_settings.js | 3 +++ 5 files changed, 31 insertions(+), 7 deletions(-) (limited to 'app/javascript/flavours/glitch/features/status') diff --git a/app/javascript/flavours/glitch/components/status.js b/app/javascript/flavours/glitch/components/status.js index 1ac5a4b3e..e0d591ff6 100644 --- a/app/javascript/flavours/glitch/components/status.js +++ b/app/javascript/flavours/glitch/components/status.js @@ -56,6 +56,7 @@ export default class Status extends ImmutablePureComponent { state = { isCollapsed: false, autoCollapsed: false, + isExpanded: this.props.settings.getIn(['content_warnings', 'auto_unfold']), } // Avoid checking props that are functions (and whose equality will always diff --git a/app/javascript/flavours/glitch/features/local_settings/navigation/index.js b/app/javascript/flavours/glitch/features/local_settings/navigation/index.js index fc2167c0c..0c1040290 100644 --- a/app/javascript/flavours/glitch/features/local_settings/navigation/index.js +++ b/app/javascript/flavours/glitch/features/local_settings/navigation/index.js @@ -10,6 +10,7 @@ import LocalSettingsNavigationItem from './item'; const messages = defineMessages({ general: { id: 'settings.general', defaultMessage: 'General' }, + content_warnings: { id: 'settings.content_warnings', defaultMessage: 'Content Warnings' }, collapsed: { id: 'settings.collapsed_statuses', defaultMessage: 'Collapsed toots' }, media: { id: 'settings.media', defaultMessage: 'Media' }, preferences: { id: 'settings.preferences', defaultMessage: 'Preferences' }, @@ -42,25 +43,31 @@ export default class LocalSettingsNavigation extends React.PureComponent { active={index === 1} index={1} onNavigate={onNavigate} - title={intl.formatMessage(messages.collapsed)} + title={intl.formatMessage(messages.content_warnings)} /> + 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 1e61c67c0..37396d970 100644 --- a/app/javascript/flavours/glitch/features/local_settings/page/index.js +++ b/app/javascript/flavours/glitch/features/local_settings/page/index.js @@ -122,6 +122,19 @@ export default class LocalSettingsPage extends React.PureComponent { ), + ({ onChange, settings }) => ( +
+

+ + + +
+ ), ({ onChange, settings }) => (

diff --git a/app/javascript/flavours/glitch/features/status/index.js b/app/javascript/flavours/glitch/features/status/index.js index 1fceaa5ea..060f2f345 100644 --- a/app/javascript/flavours/glitch/features/status/index.js +++ b/app/javascript/flavours/glitch/features/status/index.js @@ -82,8 +82,8 @@ export default class Status extends ImmutablePureComponent { state = { fullscreen: false, - isExpanded: false, - threadExpanded: null, + isExpanded: this.props.settings.getIn(['content_warnings', 'auto_unfold']), + threadExpanded: undefined, }; componentWillMount () { diff --git a/app/javascript/flavours/glitch/reducers/local_settings.js b/app/javascript/flavours/glitch/reducers/local_settings.js index ebe0b1292..ce33cac83 100644 --- a/app/javascript/flavours/glitch/reducers/local_settings.js +++ b/app/javascript/flavours/glitch/reducers/local_settings.js @@ -14,6 +14,9 @@ const initialState = ImmutableMap({ show_reply_count : false, always_show_spoilers_field: false, confirm_missing_media_description: false, + content_warnings : ImmutableMap({ + auto_unfold : false, + }), collapsed : ImmutableMap({ enabled : true, auto : ImmutableMap({ -- cgit From c6942a528332e99b605efa95ffa1c710324d368c Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Tue, 28 Aug 2018 17:16:30 +0200 Subject: Add option to not automatically unfold content warnings matching a regexp Fixes #678 --- app/javascript/flavours/glitch/components/status.js | 14 +++++++++++++- .../glitch/features/local_settings/page/index.js | 13 ++++++++++++- .../flavours/glitch/features/status/index.js | 8 +++++++- .../flavours/glitch/reducers/local_settings.js | 1 + .../flavours/glitch/util/content_warning.js | 19 +++++++++++++++++++ 5 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 app/javascript/flavours/glitch/util/content_warning.js (limited to 'app/javascript/flavours/glitch/features/status') diff --git a/app/javascript/flavours/glitch/components/status.js b/app/javascript/flavours/glitch/components/status.js index e0d591ff6..9f47abfef 100644 --- a/app/javascript/flavours/glitch/components/status.js +++ b/app/javascript/flavours/glitch/components/status.js @@ -13,6 +13,7 @@ import { MediaGallery, Video } from 'flavours/glitch/util/async-components'; import { HotKeys } from 'react-hotkeys'; import NotificationOverlayContainer from 'flavours/glitch/features/notifications/containers/overlay_container'; import classNames from 'classnames'; +import { autoUnfoldCW } from 'flavours/glitch/util/content_warning'; // We use the component (and not the container) since we do not want // to use the progress bar to show download progress @@ -56,7 +57,7 @@ export default class Status extends ImmutablePureComponent { state = { isCollapsed: false, autoCollapsed: false, - isExpanded: this.props.settings.getIn(['content_warnings', 'auto_unfold']), + isExpanded: undefined, } // Avoid checking props that are functions (and whose equality will always @@ -124,6 +125,17 @@ export default class Status extends ImmutablePureComponent { updated = true; } + if (nextProps.expanded === undefined && + prevState.isExpanded === undefined && + update.isExpanded === undefined + ) { + const isExpanded = autoUnfoldCW(nextProps.settings, nextProps.status); + if (isExpanded !== undefined) { + update.isExpanded = isExpanded; + updated = true; + } + } + return updated ? update : null; } 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 37396d970..0db49ba5d 100644 --- a/app/javascript/flavours/glitch/features/local_settings/page/index.js +++ b/app/javascript/flavours/glitch/features/local_settings/page/index.js @@ -17,6 +17,7 @@ const messages = defineMessages({ side_arm_keep: { id: 'settings.side_arm_reply_mode.keep', defaultMessage: 'Keep secondary toot button to set privacy' }, side_arm_copy: { id: 'settings.side_arm_reply_mode.copy', defaultMessage: 'Copy privacy setting of the toot being replied to' }, side_arm_restrict: { id: 'settings.side_arm_reply_mode.restrict', defaultMessage: 'Restrict privacy setting to that of the toot being replied to' }, + regexp: { id: 'settings.content_warnings.regexp', defaultMessage: 'Regular expression' }, }); @injectIntl @@ -122,7 +123,7 @@ export default class LocalSettingsPage extends React.PureComponent {
), - ({ onChange, settings }) => ( + ({ intl, onChange, settings }) => (

+ + +
), ({ onChange, settings }) => ( diff --git a/app/javascript/flavours/glitch/features/status/index.js b/app/javascript/flavours/glitch/features/status/index.js index 060f2f345..3d309976a 100644 --- a/app/javascript/flavours/glitch/features/status/index.js +++ b/app/javascript/flavours/glitch/features/status/index.js @@ -38,6 +38,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component'; import { HotKeys } from 'react-hotkeys'; import { boostModal, favouriteModal, deleteModal } from 'flavours/glitch/util/initial_state'; import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from 'flavours/glitch/util/fullscreen'; +import { autoUnfoldCW } from 'flavours/glitch/util/content_warning'; const messages = defineMessages({ deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' }, @@ -82,7 +83,7 @@ export default class Status extends ImmutablePureComponent { state = { fullscreen: false, - isExpanded: this.props.settings.getIn(['content_warnings', 'auto_unfold']), + isExpanded: undefined, threadExpanded: undefined, }; @@ -95,9 +96,14 @@ export default class Status extends ImmutablePureComponent { } componentWillReceiveProps (nextProps) { + if (this.state.isExpanded === undefined) { + const isExpanded = autoUnfoldCW(nextProps.settings, nextProps.status); + if (isExpanded !== undefined) this.setState({ isExpanded: isExpanded }); + } if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) { this._scrolledIntoView = false; this.props.dispatch(fetchStatus(nextProps.params.statusId)); + this.setState({ isExpanded: autoUnfoldCW(nextProps.settings, nextProps.status) }); } } diff --git a/app/javascript/flavours/glitch/reducers/local_settings.js b/app/javascript/flavours/glitch/reducers/local_settings.js index ce33cac83..063ae3943 100644 --- a/app/javascript/flavours/glitch/reducers/local_settings.js +++ b/app/javascript/flavours/glitch/reducers/local_settings.js @@ -16,6 +16,7 @@ const initialState = ImmutableMap({ confirm_missing_media_description: false, content_warnings : ImmutableMap({ auto_unfold : false, + filter : null, }), collapsed : ImmutableMap({ enabled : true, diff --git a/app/javascript/flavours/glitch/util/content_warning.js b/app/javascript/flavours/glitch/util/content_warning.js new file mode 100644 index 000000000..29e221c8e --- /dev/null +++ b/app/javascript/flavours/glitch/util/content_warning.js @@ -0,0 +1,19 @@ +export function autoUnfoldCW (settings, status) { + if (!settings.getIn(['content_warnings', 'auto_unfold'])) { + return false; + } + + const rawRegex = settings.getIn(['content_warnings', 'filter']); + let regex = null; + + try { + regex = rawRegex && new RegExp(rawRegex.trim(), 'i'); + } catch (e) { + // Bad regex, don't affect filters + } + + if (!(status && regex)) { + return undefined; + } + return !regex.test(status.get('spoiler_text')); +} -- cgit From bd437f80771f2700c62d45ad57cd76f1184ecfbf Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Fri, 31 Aug 2018 12:33:32 +0200 Subject: Add admin links to status and account menus (fixes #673) If the current logged-in user is an admin, add quick links to the admin interface in account and toot dropdown menu. Suggestion by @ashkitten --- app/javascript/flavours/glitch/components/status_action_bar.js | 9 ++++++++- .../flavours/glitch/features/account/components/action_bar.js | 8 +++++++- .../flavours/glitch/features/status/components/action_bar.js | 9 ++++++++- 3 files changed, 23 insertions(+), 3 deletions(-) (limited to 'app/javascript/flavours/glitch/features/status') diff --git a/app/javascript/flavours/glitch/components/status_action_bar.js b/app/javascript/flavours/glitch/components/status_action_bar.js index e26bdb717..f7e741d2d 100644 --- a/app/javascript/flavours/glitch/components/status_action_bar.js +++ b/app/javascript/flavours/glitch/components/status_action_bar.js @@ -5,7 +5,7 @@ import IconButton from './icon_button'; import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_container'; import { defineMessages, injectIntl } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import { me } from 'flavours/glitch/util/initial_state'; +import { me, isStaff } from 'flavours/glitch/util/initial_state'; import RelativeTimestamp from './relative_timestamp'; const messages = defineMessages({ @@ -31,6 +31,8 @@ const messages = defineMessages({ pin: { id: 'status.pin', defaultMessage: 'Pin on profile' }, unpin: { id: 'status.unpin', defaultMessage: 'Unpin from profile' }, embed: { id: 'status.embed', defaultMessage: 'Embed' }, + admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' }, + admin_status: { id: 'status.admin_status', defaultMessage: 'Open this status in the moderation interface' }, }); const obfuscatedCount = count => { @@ -186,6 +188,11 @@ export default class StatusActionBar extends ImmutablePureComponent { menu.push({ text: intl.formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), action: this.handleMuteClick }); menu.push({ text: intl.formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), action: this.handleBlockClick }); menu.push({ text: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport }); + if (isStaff) { + menu.push(null); + menu.push({ text: intl.formatMessage(messages.admin_account, { name: status.getIn(['account', 'username']) }), href: `/admin/accounts/${status.getIn(['account', 'id'])}` }); + menu.push({ text: intl.formatMessage(messages.admin_status), href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses/${status.get('id')}` }); + } } if (status.get('in_reply_to_id', null) === null) { diff --git a/app/javascript/flavours/glitch/features/account/components/action_bar.js b/app/javascript/flavours/glitch/features/account/components/action_bar.js index 9c80a470b..26717ee49 100644 --- a/app/javascript/flavours/glitch/features/account/components/action_bar.js +++ b/app/javascript/flavours/glitch/features/account/components/action_bar.js @@ -4,7 +4,7 @@ import PropTypes from 'prop-types'; import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_container'; import { Link } from 'react-router-dom'; import { defineMessages, injectIntl, FormattedMessage, FormattedNumber } from 'react-intl'; -import { me } from 'flavours/glitch/util/initial_state'; +import { me, isStaff } from 'flavours/glitch/util/initial_state'; const messages = defineMessages({ mention: { id: 'account.mention', defaultMessage: 'Mention @{name}' }, @@ -25,6 +25,7 @@ const messages = defineMessages({ showReblogs: { id: 'account.show_reblogs', defaultMessage: 'Show boosts from @{name}' }, endorse: { id: 'account.endorse', defaultMessage: 'Feature on profile' }, unendorse: { id: 'account.unendorse', defaultMessage: 'Don\'t feature on profile' }, + admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' }, }); @injectIntl @@ -120,6 +121,11 @@ export default class ActionBar extends React.PureComponent { } } + if (account.get('id') !== me && isStaff) { + menu.push(null); + menu.push({ text: intl.formatMessage(messages.admin_account, { name: account.get('username') }), href: `/admin/accounts/${account.get('id')}` }); + } + return (
{extraInfo} diff --git a/app/javascript/flavours/glitch/features/status/components/action_bar.js b/app/javascript/flavours/glitch/features/status/components/action_bar.js index 413833a79..009aa49eb 100644 --- a/app/javascript/flavours/glitch/features/status/components/action_bar.js +++ b/app/javascript/flavours/glitch/features/status/components/action_bar.js @@ -4,7 +4,7 @@ import IconButton from 'flavours/glitch/components/icon_button'; import ImmutablePropTypes from 'react-immutable-proptypes'; import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_container'; import { defineMessages, injectIntl } from 'react-intl'; -import { me } from 'flavours/glitch/util/initial_state'; +import { me, isStaff } from 'flavours/glitch/util/initial_state'; const messages = defineMessages({ delete: { id: 'status.delete', defaultMessage: 'Delete' }, @@ -26,6 +26,8 @@ const messages = defineMessages({ pin: { id: 'status.pin', defaultMessage: 'Pin on profile' }, unpin: { id: 'status.unpin', defaultMessage: 'Unpin from profile' }, embed: { id: 'status.embed', defaultMessage: 'Embed' }, + admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' }, + admin_status: { id: 'status.admin_status', defaultMessage: 'Open this status in the moderation interface' }, }); @injectIntl @@ -146,6 +148,11 @@ export default class ActionBar extends React.PureComponent { menu.push({ text: intl.formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), action: this.handleMuteClick }); menu.push({ text: intl.formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), action: this.handleBlockClick }); menu.push({ text: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport }); + if (isStaff) { + menu.push(null); + menu.push({ text: intl.formatMessage(messages.admin_account, { name: status.getIn(['account', 'username']) }), href: `/admin/accounts/${status.getIn(['account', 'id'])}` }); + menu.push({ text: intl.formatMessage(messages.admin_status), href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses/${status.get('id')}` }); + } } const shareButton = ('share' in navigator) && status.get('visibility') === 'public' && ( -- cgit