diff options
Diffstat (limited to 'app')
10 files changed, 52 insertions, 10 deletions
diff --git a/app/javascript/mastodon/components/status_action_bar.js b/app/javascript/mastodon/components/status_action_bar.js index 53d17d418..0bfbd8879 100644 --- a/app/javascript/mastodon/components/status_action_bar.js +++ b/app/javascript/mastodon/components/status_action_bar.js @@ -139,7 +139,7 @@ class StatusActionBar extends ImmutablePureComponent { } handleBlockClick = () => { - this.props.onBlock(this.props.status.get('account')); + this.props.onBlock(this.props.status); } handleOpen = () => { diff --git a/app/javascript/mastodon/containers/status_container.js b/app/javascript/mastodon/containers/status_container.js index b3555c76e..0fce674e2 100644 --- a/app/javascript/mastodon/containers/status_container.js +++ b/app/javascript/mastodon/containers/status_container.js @@ -38,6 +38,7 @@ const messages = defineMessages({ blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' }, 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' }, }); const makeMapStateToProps = () => { @@ -134,11 +135,17 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ dispatch(openModal('VIDEO', { media, time })); }, - onBlock (account) { + onBlock (status) { + const account = status.get('account'); dispatch(openModal('CONFIRM', { message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />, confirm: intl.formatMessage(messages.blockConfirm), onConfirm: () => dispatch(blockAccount(account.get('id'))), + secondary: intl.formatMessage(messages.blockAndReport), + onSecondary: () => { + dispatch(blockAccount(account.get('id'))); + dispatch(initReport(account, status)); + }, })); }, diff --git a/app/javascript/mastodon/features/account/components/header.js b/app/javascript/mastodon/features/account/components/header.js index 41e394585..fd7ad5e07 100644 --- a/app/javascript/mastodon/features/account/components/header.js +++ b/app/javascript/mastodon/features/account/components/header.js @@ -212,7 +212,7 @@ class Header extends ImmutablePureComponent { <div className='account__header__bar'> <div className='account__header__tabs'> - <a className='avatar' href={account.get('url')}> + <a className='avatar' href={account.get('url')} target='_blank'> <Avatar account={account} size={90} /> </a> diff --git a/app/javascript/mastodon/features/account_timeline/containers/header_container.js b/app/javascript/mastodon/features/account_timeline/containers/header_container.js index df742f9ec..a06a0b095 100644 --- a/app/javascript/mastodon/features/account_timeline/containers/header_container.js +++ b/app/javascript/mastodon/features/account_timeline/containers/header_container.js @@ -26,6 +26,7 @@ const messages = defineMessages({ unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' }, blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' }, blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' }, + blockAndReport: { id: 'confirmations.block.block_and_report', defaultMessage: 'Block & Report' }, }); const makeMapStateToProps = () => { @@ -65,6 +66,11 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />, confirm: intl.formatMessage(messages.blockConfirm), onConfirm: () => dispatch(blockAccount(account.get('id'))), + secondary: intl.formatMessage(messages.blockAndReport), + onSecondary: () => { + dispatch(blockAccount(account.get('id'))); + dispatch(initReport(account)); + }, })); } }, diff --git a/app/javascript/mastodon/features/status/components/action_bar.js b/app/javascript/mastodon/features/status/components/action_bar.js index 73be1fc5f..3e511b7a6 100644 --- a/app/javascript/mastodon/features/status/components/action_bar.js +++ b/app/javascript/mastodon/features/status/components/action_bar.js @@ -92,7 +92,7 @@ class ActionBar extends React.PureComponent { } handleBlockClick = () => { - this.props.onBlock(this.props.status.get('account')); + this.props.onBlock(this.props.status); } handleReport = () => { diff --git a/app/javascript/mastodon/features/status/containers/detailed_status_container.js b/app/javascript/mastodon/features/status/containers/detailed_status_container.js index 2c0db0a6b..61e0c428a 100644 --- a/app/javascript/mastodon/features/status/containers/detailed_status_container.js +++ b/app/javascript/mastodon/features/status/containers/detailed_status_container.js @@ -38,6 +38,7 @@ const messages = defineMessages({ blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' }, 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' }, }); const makeMapStateToProps = () => { @@ -135,11 +136,17 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ dispatch(openModal('VIDEO', { media, time })); }, - onBlock (account) { + onBlock (status) { + const account = status.get('account'); dispatch(openModal('CONFIRM', { message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />, confirm: intl.formatMessage(messages.blockConfirm), onConfirm: () => dispatch(blockAccount(account.get('id'))), + secondary: intl.formatMessage(messages.blockAndReport), + onSecondary: () => { + dispatch(blockAccount(account.get('id'))); + dispatch(initReport(account, status)); + }, })); }, diff --git a/app/javascript/mastodon/features/status/index.js b/app/javascript/mastodon/features/status/index.js index 3b5febcac..c0ea460e8 100644 --- a/app/javascript/mastodon/features/status/index.js +++ b/app/javascript/mastodon/features/status/index.js @@ -57,6 +57,7 @@ const messages = defineMessages({ detailedStatus: { id: 'status.detailed_status', defaultMessage: 'Detailed conversation view' }, 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' }, }); const makeMapStateToProps = () => { @@ -253,13 +254,19 @@ class Status extends ImmutablePureComponent { } } - handleBlockClick = (account) => { + handleBlockClick = (status) => { const { dispatch, intl } = this.props; + const account = status.get('account'); dispatch(openModal('CONFIRM', { message: <FormattedMessage id='confirmations.block.message' defaultMessage='Are you sure you want to block {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />, confirm: intl.formatMessage(messages.blockConfirm), onConfirm: () => dispatch(blockAccount(account.get('id'))), + secondary: intl.formatMessage(messages.blockAndReport), + onSecondary: () => { + dispatch(blockAccount(account.get('id'))); + dispatch(initReport(account, status)); + }, })); } diff --git a/app/javascript/mastodon/features/ui/components/confirmation_modal.js b/app/javascript/mastodon/features/ui/components/confirmation_modal.js index f0f3ad134..1227fa453 100644 --- a/app/javascript/mastodon/features/ui/components/confirmation_modal.js +++ b/app/javascript/mastodon/features/ui/components/confirmation_modal.js @@ -11,6 +11,8 @@ class ConfirmationModal extends React.PureComponent { confirm: PropTypes.string.isRequired, onClose: PropTypes.func.isRequired, onConfirm: PropTypes.func.isRequired, + secondary: PropTypes.string, + onSecondary: PropTypes.func, intl: PropTypes.object.isRequired, }; @@ -23,6 +25,11 @@ class ConfirmationModal extends React.PureComponent { this.props.onConfirm(); } + handleSecondary = () => { + this.props.onClose(); + this.props.onSecondary(); + } + handleCancel = () => { this.props.onClose(); } @@ -32,7 +39,7 @@ class ConfirmationModal extends React.PureComponent { } render () { - const { message, confirm } = this.props; + const { message, confirm, secondary } = this.props; return ( <div className='modal-root__modal confirmation-modal'> @@ -44,6 +51,9 @@ class ConfirmationModal extends React.PureComponent { <Button onClick={this.handleCancel} className='confirmation-modal__cancel-button'> <FormattedMessage id='confirmation_modal.cancel' defaultMessage='Cancel' /> </Button> + {secondary !== undefined && ( + <Button text={secondary} onClick={this.handleSecondary} className='confirmation-modal__secondary-button' /> + )} <Button text={confirm} onClick={this.handleClick} ref={this.setRef} /> </div> </div> diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index e26341149..53c392062 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -4128,6 +4128,7 @@ a.status-card.compact:hover { .confirmation-modal__action-bar, .mute-modal__action-bar { + .confirmation-modal__secondary-button, .confirmation-modal__cancel-button, .mute-modal__cancel-button { background-color: transparent; diff --git a/app/validators/html_validator.rb b/app/validators/html_validator.rb index 882c35d41..b7caee5a9 100644 --- a/app/validators/html_validator.rb +++ b/app/validators/html_validator.rb @@ -3,12 +3,16 @@ class HtmlValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) return if value.blank? - record.errors.add(attribute, I18n.t('html_validator.invalid_markup')) unless valid_html?(value) + errors = html_errors(value) + unless errors.empty? + record.errors.add(attribute, I18n.t('html_validator.invalid_markup', error: errors.first.to_s)) + end end private - def valid_html?(str) - Nokogiri::HTML.fragment(str).to_s == str + def html_errors(str) + fragment = Nokogiri::HTML.fragment(str) + fragment.errors end end |