diff --git a/app/javascript/mastodon/actions/compose.js b/app/javascript/mastodon/actions/compose.js
index 0fe4800227..130b4af239 100644
--- a/app/javascript/mastodon/actions/compose.js
+++ b/app/javascript/mastodon/actions/compose.js
@@ -96,8 +96,9 @@ export function mentionCompose(account, router) {
export function submitCompose() {
return function (dispatch, getState) {
const status = getState().getIn(['compose', 'text'], '');
+ const media = getState().getIn(['compose', 'media_attachments']);
- if (!status || !status.length) {
+ if ((!status || !status.length) && media.size === 0) {
return;
}
@@ -106,7 +107,7 @@ export function submitCompose() {
api(getState).post('/api/v1/statuses', {
status,
in_reply_to_id: getState().getIn(['compose', 'in_reply_to'], null),
- media_ids: getState().getIn(['compose', 'media_attachments']).map(item => item.get('id')),
+ media_ids: media.map(item => item.get('id')),
sensitive: getState().getIn(['compose', 'sensitive']),
spoiler_text: getState().getIn(['compose', 'spoiler_text'], ''),
visibility: getState().getIn(['compose', 'privacy']),
diff --git a/app/javascript/mastodon/components/status_content.js b/app/javascript/mastodon/components/status_content.js
index 3b81556329..701b5702cc 100644
--- a/app/javascript/mastodon/components/status_content.js
+++ b/app/javascript/mastodon/components/status_content.js
@@ -24,7 +24,12 @@ export default class StatusContent extends React.PureComponent {
};
_updateStatusLinks () {
- const node = this.node;
+ const node = this.node;
+
+ if (!node) {
+ return;
+ }
+
const links = node.querySelectorAll('a');
for (var i = 0; i < links.length; ++i) {
@@ -115,6 +120,10 @@ export default class StatusContent extends React.PureComponent {
render () {
const { status } = this.props;
+ if (status.get('content').length === 0) {
+ return null;
+ }
+
const hidden = this.props.onExpandedToggle ? !this.props.expanded : this.state.hidden;
const content = { __html: status.get('contentHtml') };
diff --git a/app/javascript/mastodon/features/compose/components/compose_form.js b/app/javascript/mastodon/features/compose/components/compose_form.js
index a876c5197e..663ccfb8ea 100644
--- a/app/javascript/mastodon/features/compose/components/compose_form.js
+++ b/app/javascript/mastodon/features/compose/components/compose_form.js
@@ -50,6 +50,7 @@ export default class ComposeForm extends ImmutablePureComponent {
onPaste: PropTypes.func.isRequired,
onPickEmoji: PropTypes.func.isRequired,
showSearch: PropTypes.bool,
+ anyMedia: PropTypes.bool,
};
static defaultProps = {
@@ -142,10 +143,10 @@ export default class ComposeForm extends ImmutablePureComponent {
}
render () {
- const { intl, onPaste, showSearch } = this.props;
+ const { intl, onPaste, showSearch, anyMedia } = this.props;
const disabled = this.props.is_submitting;
const text = [this.props.spoiler_text, countableText(this.props.text)].join('');
-
+ const disabledButton = disabled || this.props.is_uploading || length(text) > 500 || (text.length !== 0 && text.trim().length === 0 && !anyMedia);
let publishText = '';
if (this.props.privacy === 'private' || this.props.privacy === 'direct') {
@@ -203,7 +204,7 @@ export default class ComposeForm extends ImmutablePureComponent {
-
+
);
diff --git a/app/javascript/mastodon/features/compose/containers/compose_form_container.js b/app/javascript/mastodon/features/compose/containers/compose_form_container.js
index 5f5509dbea..ede23d3610 100644
--- a/app/javascript/mastodon/features/compose/containers/compose_form_container.js
+++ b/app/javascript/mastodon/features/compose/containers/compose_form_container.js
@@ -23,6 +23,7 @@ const mapStateToProps = state => ({
is_submitting: state.getIn(['compose', 'is_submitting']),
is_uploading: state.getIn(['compose', 'is_uploading']),
showSearch: state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']),
+ anyMedia: state.getIn(['compose', 'media_attachments']).size > 0,
});
const mapDispatchToProps = (dispatch) => ({
diff --git a/app/javascript/mastodon/reducers/compose.js b/app/javascript/mastodon/reducers/compose.js
index dc88390dfd..532f4b2a70 100644
--- a/app/javascript/mastodon/reducers/compose.js
+++ b/app/javascript/mastodon/reducers/compose.js
@@ -90,7 +90,6 @@ function appendMedia(state, media) {
map.update('media_attachments', list => list.push(media));
map.set('is_uploading', false);
map.set('resetFileKey', Math.floor((Math.random() * 0x10000)));
- map.update('text', oldText => `${oldText.trim()} ${media.get('text_url')}`);
map.set('focusDate', new Date());
map.set('idempotencyKey', uuid());
@@ -101,12 +100,10 @@ function appendMedia(state, media) {
};
function removeMedia(state, mediaId) {
- const media = state.get('media_attachments').find(item => item.get('id') === mediaId);
const prevSize = state.get('media_attachments').size;
return state.withMutations(map => {
map.update('media_attachments', list => list.filterNot(item => item.get('id') === mediaId));
- map.update('text', text => text.replace(media.get('text_url'), '').trim());
map.set('idempotencyKey', uuid());
if (prevSize === 1) {
diff --git a/app/lib/formatter.rb b/app/lib/formatter.rb
index 8c0f8cebce..1df4ff8d47 100644
--- a/app/lib/formatter.rb
+++ b/app/lib/formatter.rb
@@ -19,6 +19,8 @@ class Formatter
raw_content = status.text
+ return '' if raw_content.blank?
+
unless status.local?
html = reformat(raw_content)
html = encode_custom_emojis(html, status.emojis) if options[:custom_emojify]
diff --git a/app/models/status.rb b/app/models/status.rb
index f806a59fcb..60fa7a22eb 100644
--- a/app/models/status.rb
+++ b/app/models/status.rb
@@ -57,7 +57,7 @@ class Status < ApplicationRecord
has_one :stream_entry, as: :activity, inverse_of: :status
validates :uri, uniqueness: true, presence: true, unless: :local?
- validates :text, presence: true, unless: :reblog?
+ validates :text, presence: true, unless: -> { with_media? || reblog? }
validates_with StatusLengthValidator
validates :reblog, uniqueness: { scope: :account }, if: :reblog?
@@ -150,8 +150,12 @@ class Status < ApplicationRecord
private_visibility? || direct_visibility?
end
+ def with_media?
+ media_attachments.any?
+ end
+
def non_sensitive_with_media?
- !sensitive? && media_attachments.any?
+ !sensitive? && with_media?
end
def emojis
diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb
index 92d868afe4..df38d16a6c 100644
--- a/app/services/post_status_service.rb
+++ b/app/services/post_status_service.rb
@@ -21,17 +21,17 @@ class PostStatusService < BaseService
media = validate_media!(options[:media_ids])
status = nil
+ text = options.delete(:spoiler_text) if text.blank? && options[:spoiler_text].present?
ApplicationRecord.transaction do
status = account.statuses.create!(text: text,
+ media_attachments: media || [],
thread: in_reply_to,
sensitive: options[:sensitive],
spoiler_text: options[:spoiler_text] || '',
visibility: options[:visibility] || account.user&.setting_default_privacy,
language: LanguageDetector.instance.detect(text, account),
application: options[:application])
-
- attach_media(status, media)
end
process_mentions_service.call(status)
@@ -64,11 +64,6 @@ class PostStatusService < BaseService
media
end
- def attach_media(status, media)
- return if media.nil?
- media.update(status_id: status.id)
- end
-
def process_mentions_service
ProcessMentionsService.new
end