diff --git a/Gruntfile.js b/Gruntfile.js index 94ffff340..cb875befd 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -167,7 +167,10 @@ module.exports = function(grunt) { '!js/modules/**/*.js', '!js/models/conversations.js', '!js/models/messages.js', + '!js/views/conversation_search_view.js', '!js/views/conversation_view.js', + '!js/views/debug_log_view.js', + '!js/views/message_view.js', '!js/Mp3LameEncoder.min.js', '!js/WebAudioRecorderMp3.js', 'test/**/*.js', diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 1353ea19e..85251a2b6 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -546,6 +546,10 @@ "message": "Secure session reset", "description": "This is a past tense, informational message. In other words, your secure session has been reset." }, + "noContents": { + "message": "No message contents", + "description": "Shown in a message bubble if we have nothing in the message to display, or a quote and nothing else" + }, "installWelcome": { "message": "Welcome to Signal Desktop", "description": "Welcome title on the install page" diff --git a/js/views/message_view.js b/js/views/message_view.js index 38bbcf353..3c9a122b2 100644 --- a/js/views/message_view.js +++ b/js/views/message_view.js @@ -349,6 +349,12 @@ } this.errorIconView = new ErrorIconView({ model: errors[0] }); this.errorIconView.render().$el.appendTo(this.$('.bubble')); + } else if (!this.hasContents()) { + const el = this.$('.content'); + if (!el || el.length === 0) { + this.$('.inner-bubble').append("
"); + } + this.$('.content').text(i18n('noContents')).addClass('error-message'); } this.$('.meta .hasRetry').remove(); @@ -429,18 +435,34 @@ return false; }, + hasContents() { + const attachments = this.model.get('attachments'); + const hasAttachments = attachments && attachments.length > 0; + + return this.hasTextContents() || hasAttachments; + }, + hasTextContents() { + const body = this.model.get('body'); + const isGroupUpdate = this.model.isGroupUpdate(); + const isEndSession = this.model.isEndSession(); + + const errors = this.model.get('errors'); + const hasErrors = errors && errors.length > 0; + const errorsCanBeContents = this.model.isIncoming() && hasErrors; + + return body || isGroupUpdate || isEndSession || errorsCanBeContents; + }, render() { const contact = this.model.isIncoming() ? this.model.getContact() : null; - const errors = this.model.get('errors'); const attachments = this.model.get('attachments'); - const hasErrors = errors && errors.length > 0; + // TODO: used for the feature flag below + // const hasErrors = errors && errors.length > 0; const hasAttachments = attachments && attachments.length > 0; - const message = this.model.get('body'); - const hasBody = message || (this.model.isIncoming() && hasErrors); + const hasBody = this.hasTextContents(); this.$el.html(Mustache.render(_.result(this, 'template', ''), { - message, + message: this.model.get('body'), hasBody, timestamp: this.model.get('sent_at'), sender: (contact && contact.getTitle()) || '', diff --git a/ts/components/conversation/Message.md b/ts/components/conversation/Message.md index bf294bfb2..116d365b9 100644 --- a/ts/components/conversation/Message.md +++ b/ts/components/conversation/Message.md @@ -133,6 +133,31 @@ const View = Whisper.MessageView; ``` +#### No message contents + +```jsx +const outgoing = new Whisper.Message({ + type: 'outgoing', + sent_at: Date.now() - 200000, +}); +const incoming = new Whisper.Message(Object.assign({}, outgoing.attributes, { + source: '+12025550003', + type: 'incoming', +})); + +const View = Whisper.MessageView; +