diff --git a/app/javascript/flavours/glitch/components/status.js b/app/javascript/flavours/glitch/components/status.js
index 022ae6de85..973275fbba 100644
--- a/app/javascript/flavours/glitch/components/status.js
+++ b/app/javascript/flavours/glitch/components/status.js
@@ -106,6 +106,7 @@ class Status extends ImmutablePureComponent {
statusId: undefined,
revealBehindCW: undefined,
showCard: false,
+ bypassFilter: false,
}
// Avoid checking props that are functions (and whose equality will always
@@ -126,6 +127,7 @@ class Status extends ImmutablePureComponent {
'isExpanded',
'isCollapsed',
'showMedia',
+ 'bypassFilter',
]
// If our settings have changed to disable collapsed statuses, then we
@@ -427,6 +429,15 @@ class Status extends ImmutablePureComponent {
this.handleToggleMediaVisibility();
}
+ handleUnfilterClick = e => {
+ const { onUnfilter, status } = this.props;
+ onUnfilter(status.get('reblog') ? status.get('reblog') : status, () => this.setState({ bypassFilter: true }));
+ }
+
+ handleFilterClick = () => {
+ this.setState({ bypassFilter: false });
+ }
+
handleRef = c => {
this.node = c;
}
@@ -485,7 +496,7 @@ class Status extends ImmutablePureComponent {
);
}
- if (status.get('filtered') || status.getIn(['reblog', 'filtered'])) {
+ if ((status.get('filtered') || status.getIn(['reblog', 'filtered'])) && !this.state.bypassFilter) {
const minHandlers = this.props.muted ? {} : {
moveUp: this.handleHotkeyMoveUp,
moveDown: this.handleHotkeyMoveDown,
@@ -495,6 +506,9 @@ class Status extends ImmutablePureComponent {
+
);
@@ -689,6 +703,7 @@ class Status extends ImmutablePureComponent {
account={status.get('account')}
showReplyCount={settings.get('show_reply_count')}
directMessage={!!otherAccounts}
+ onFilter={this.handleFilterClick}
/>
) : null}
{notification ? (
diff --git a/app/javascript/flavours/glitch/components/status_action_bar.js b/app/javascript/flavours/glitch/components/status_action_bar.js
index c424fbde13..4ef518f5e9 100644
--- a/app/javascript/flavours/glitch/components/status_action_bar.js
+++ b/app/javascript/flavours/glitch/components/status_action_bar.js
@@ -35,6 +35,7 @@ const messages = defineMessages({
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' },
copy: { id: 'status.copy', defaultMessage: 'Copy link to status' },
+ hide: { id: 'status.hide', defaultMessage: 'Hide toot' },
});
const obfuscatedCount = count => {
@@ -69,6 +70,7 @@ export default class StatusActionBar extends ImmutablePureComponent {
onMuteConversation: PropTypes.func,
onPin: PropTypes.func,
onBookmark: PropTypes.func,
+ onFilter: PropTypes.func,
withDismiss: PropTypes.bool,
showReplyCount: PropTypes.bool,
directMessage: PropTypes.bool,
@@ -191,6 +193,10 @@ export default class StatusActionBar extends ImmutablePureComponent {
}
}
+ handleFilterClick = () => {
+ this.props.onFilter();
+ }
+
render () {
const { status, intl, withDismiss, showReplyCount, directMessage } = this.props;
@@ -263,6 +269,10 @@ export default class StatusActionBar extends ImmutablePureComponent {
);
+ const filterButton = status.get('filtered') && (
+
+ );
+
let replyButton = (
,
shareButton,
,
+ filterButton,
,
diff --git a/app/javascript/flavours/glitch/containers/status_container.js b/app/javascript/flavours/glitch/containers/status_container.js
index a6069cb905..ba12ad38d5 100644
--- a/app/javascript/flavours/glitch/containers/status_container.js
+++ b/app/javascript/flavours/glitch/containers/status_container.js
@@ -1,7 +1,8 @@
import React from 'react';
import { connect } from 'react-redux';
import Status from 'flavours/glitch/components/status';
-import { makeGetStatus } from 'flavours/glitch/selectors';
+import { List as ImmutableList } from 'immutable';
+import { makeGetStatus, regexFromFilters, toServerSideType } from 'flavours/glitch/selectors';
import {
replyCompose,
mentionCompose,
@@ -26,6 +27,7 @@ import { changeLocalSetting } from 'flavours/glitch/actions/local_settings';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import { boostModal, favouriteModal, deleteModal } from 'flavours/glitch/util/initial_state';
import { showAlertForError } from '../actions/alerts';
+import AccountContainer from 'flavours/glitch/containers/account_container';
const messages = defineMessages({
deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
@@ -36,8 +38,49 @@ const messages = defineMessages({
replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' },
replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
blockAndReport: { id: 'confirmations.block.block_and_report', defaultMessage: 'Block & Report' },
+ unfilterConfirm: { id: 'confirmations.unfilter.confirm', defaultMessage: 'Show' },
});
+class SpoilerMachin extends React.PureComponent {
+ state = {
+ hidden: true,
+ }
+
+ handleSpoilerClick = () => {
+ this.setState({ hidden: !this.state.hidden });
+ }
+
+ render () {
+ const { spoilerText, children } = this.props;
+ const { hidden } = this.state;
+
+ const toggleText = hidden ?
+ :
+ ;
+
+ return ([
+
+ {spoilerText}
+ {' '}
+
+
,
+
+ {children}
+
+ ]);
+ }
+}
+
const makeMapStateToProps = () => {
const getStatus = makeGetStatus();
@@ -69,7 +112,7 @@ const makeMapStateToProps = () => {
return mapStateToProps;
};
-const mapDispatchToProps = (dispatch, { intl }) => ({
+const mapDispatchToProps = (dispatch, { intl, contextType }) => ({
onReply (status, router) {
dispatch((_, getState) => {
@@ -189,6 +232,33 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
}));
},
+ onUnfilter (status, onConfirm) {
+ dispatch((_, getState) => {
+ let state = getState();
+ const serverSideType = toServerSideType(contextType);
+ const enabledFilters = state.get('filters', ImmutableList()).filter(filter => filter.get('context').includes(serverSideType) && (filter.get('expires_at') === null || Date.parse(filter.get('expires_at')) > (new Date()))).toArray();
+ const searchIndex = status.get('search_index');
+ const matchingFilters = enabledFilters.filter(filter => regexFromFilters([filter]).test(searchIndex));
+ dispatch(openModal('CONFIRM', {
+ message: [
+ ,
+
+
+
+
+
+
+ {matchingFilters.map(filter => - {filter.get('phrase')}
)}
+
+
+
+ ],
+ confirm: intl.formatMessage(messages.unfilterConfirm),
+ onConfirm: onConfirm,
+ }));
+ });
+ },
+
onReport (status) {
dispatch(initReport(status.get('account'), status));
},
diff --git a/app/javascript/flavours/glitch/selectors/index.js b/app/javascript/flavours/glitch/selectors/index.js
index 9e45825327..3424058d30 100644
--- a/app/javascript/flavours/glitch/selectors/index.js
+++ b/app/javascript/flavours/glitch/selectors/index.js
@@ -20,7 +20,7 @@ export const makeGetAccount = () => {
});
};
-const toServerSideType = columnType => {
+export const toServerSideType = columnType => {
switch (columnType) {
case 'home':
case 'notifications':
@@ -39,7 +39,7 @@ const toServerSideType = columnType => {
const escapeRegExp = string =>
string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
-const regexFromFilters = filters => {
+export const regexFromFilters = filters => {
if (filters.size === 0) {
return null;
}
diff --git a/app/javascript/flavours/glitch/styles/components/modal.scss b/app/javascript/flavours/glitch/styles/components/modal.scss
index 65b2e75f0a..b219688402 100644
--- a/app/javascript/flavours/glitch/styles/components/modal.scss
+++ b/app/javascript/flavours/glitch/styles/components/modal.scss
@@ -820,3 +820,33 @@
left: 0;
}
}
+
+.filtered-status-info {
+ text-align: start;
+
+ .spoiler__text {
+ margin-top: 20px;
+ }
+
+ .account {
+ border-bottom: 0;
+ }
+
+ .account__display-name strong {
+ color: $inverted-text-color;
+ }
+
+ .status__content__spoiler {
+ display: none;
+
+ &--visible {
+ display: flex;
+ }
+ }
+
+ ul {
+ padding: 10px;
+ margin-left: 12px;
+ list-style: disc inside;
+ }
+}
diff --git a/app/javascript/flavours/glitch/styles/components/status.scss b/app/javascript/flavours/glitch/styles/components/status.scss
index fa115f21bd..cf8f396930 100644
--- a/app/javascript/flavours/glitch/styles/components/status.scss
+++ b/app/javascript/flavours/glitch/styles/components/status.scss
@@ -996,3 +996,19 @@ a.status-card.compact:hover {
}
}
}
+
+.status__wrapper--filtered__button {
+ display: block;
+ font-size: 15px;
+ line-height: 20px;
+ color: lighten($ui-highlight-color, 8%);
+ border: 0;
+ background: transparent;
+ padding: 0;
+ padding-top: 8px;
+
+ &:hover,
+ &:active {
+ text-decoration: underline;
+ }
+}