Style resend button as an inline link
For messages that failed to send due to network errors, this change allows retrying them directly from the main conversation view rather than only from the message detail view. // FREEBIE
This commit is contained in:
parent
c48484e04f
commit
3901bcb8df
7 changed files with 100 additions and 90 deletions
|
@ -238,5 +238,9 @@
|
|||
"restartSignal": {
|
||||
"message": "Restart Signal",
|
||||
"description": "Menu item for restarting the program."
|
||||
},
|
||||
"messageNotSent": {
|
||||
"message": "Message not sent.",
|
||||
"description": "Informational label, appears on messages that failed to send"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,6 +110,10 @@
|
|||
<img src='{{ source }}' class='preview' />
|
||||
<div class='close'>x</div>
|
||||
</script>
|
||||
<script type='text/x-tmpl-mustache' id='hasRetry'>
|
||||
{{ messageNotSent }}
|
||||
<span href='#' class='retry'>{{ resend }}</span>
|
||||
</script>
|
||||
<script type='text/x-tmpl-mustache' id='message'>
|
||||
{{> avatar }}
|
||||
<div class='bubble'>
|
||||
|
@ -196,12 +200,6 @@
|
|||
</script>
|
||||
<script type='text/x-tmpl-mustache' id='message-detail'>
|
||||
<div class='container'>
|
||||
{{ #hasRetry }}
|
||||
<div class='hasRetry clearfix'>
|
||||
<h3 class='retryMessage'>{{ failedToSend }}</h3>
|
||||
<button class='retry'>{{ resend }}</button>
|
||||
</div>
|
||||
{{ /hasRetry }}
|
||||
{{ #hasConflict }}
|
||||
<div class='hasConflict clearfix'>
|
||||
<div class='conflicts'>
|
||||
|
|
|
@ -211,6 +211,14 @@
|
|||
this.set({errors: errors});
|
||||
},
|
||||
|
||||
hasNetworkError: function(number) {
|
||||
var error = _.find(this.get('errors'), function(e) {
|
||||
return (e.name === 'MessageError' ||
|
||||
e.name === 'OutgoingMessageError' ||
|
||||
e.name === 'SendMessageNetworkError');
|
||||
});
|
||||
return !!error;
|
||||
},
|
||||
removeOutgoingErrors: function(number) {
|
||||
var errors = _.partition(this.get('errors'), function(e) {
|
||||
return e.number === number &&
|
||||
|
|
|
@ -38,8 +38,7 @@
|
|||
this.listenTo(this.model, 'change', this.render);
|
||||
},
|
||||
events: {
|
||||
'click .back': 'goBack',
|
||||
'click .retry': 'retryMessage',
|
||||
'click .back': 'goBack'
|
||||
},
|
||||
goBack: function() {
|
||||
this.trigger('back');
|
||||
|
@ -65,16 +64,6 @@
|
|||
return this.conversation.contactCollection.models;
|
||||
}
|
||||
},
|
||||
retryMessage: function() {
|
||||
var retrys = _.filter(this.model.get('errors'), function(e) {
|
||||
return (e.name === 'MessageError' ||
|
||||
e.name === 'OutgoingMessageError' ||
|
||||
e.name === 'SendMessageNetworkError');
|
||||
});
|
||||
_.map(retrys, 'number').forEach(function(number) {
|
||||
this.model.resend(number);
|
||||
}.bind(this));
|
||||
},
|
||||
renderContact: function(contact) {
|
||||
var view = new ContactView({
|
||||
model: contact,
|
||||
|
@ -105,11 +94,6 @@
|
|||
},
|
||||
render: function() {
|
||||
this.errors = _.groupBy(this.model.get('errors'), 'number');
|
||||
var hasRetry = _.find(this.model.get('errors'), function(e) {
|
||||
return (e.name === 'MessageError' ||
|
||||
e.name === 'OutgoingMessageError' ||
|
||||
e.name === 'SendMessageNetworkError');
|
||||
});
|
||||
var unknownErrors = this.errors['undefined'];
|
||||
if (unknownErrors) {
|
||||
unknownErrors = unknownErrors.filter(function(e) {
|
||||
|
@ -124,10 +108,7 @@
|
|||
title : i18n('messageDetail'),
|
||||
sent : i18n('sent'),
|
||||
received : i18n('received'),
|
||||
resend : i18n('resend'),
|
||||
failedToSend: i18n('failedToSend'),
|
||||
errorLabel : i18n('error'),
|
||||
hasRetry : hasRetry,
|
||||
hasConflict : this.model.hasKeyConflicts()
|
||||
}));
|
||||
this.view.$el.prependTo(this.$('.message-container'));
|
||||
|
|
|
@ -7,6 +7,16 @@
|
|||
|
||||
var URL_REGEX = /(^|[\s\n]|<br\/?>)((?:https?|ftp):\/\/[\-A-Z0-9\u00A0-\uD7FF\uE000-\uFDCF\uFDF0-\uFFFD+\u0026\u2019@#\/%?=()~_|!:,.;]*[\-A-Z0-9+\u0026@#\/%=~()_|])/gi;
|
||||
|
||||
var NetworkErrorView = Whisper.View.extend({
|
||||
tagName: 'span',
|
||||
className: 'hasRetry',
|
||||
templateName: 'hasRetry',
|
||||
render_attributes: {
|
||||
messageNotSent: i18n('messageNotSent'),
|
||||
resend: i18n('resend')
|
||||
}
|
||||
});
|
||||
|
||||
Whisper.MessageView = Whisper.View.extend({
|
||||
tagName: 'li',
|
||||
templateName: 'message',
|
||||
|
@ -22,9 +32,21 @@
|
|||
this.timeStampView = new Whisper.ExtendedTimestampView();
|
||||
},
|
||||
events: {
|
||||
'click .meta': 'select',
|
||||
'click .retry': 'retryMessage',
|
||||
'click .timestamp': 'select',
|
||||
'click .status': 'select',
|
||||
'click .error': 'select'
|
||||
},
|
||||
retryMessage: function() {
|
||||
var retrys = _.filter(this.model.get('errors'), function(e) {
|
||||
return (e.name === 'MessageError' ||
|
||||
e.name === 'OutgoingMessageError' ||
|
||||
e.name === 'SendMessageNetworkError');
|
||||
});
|
||||
_.map(retrys, 'number').forEach(function(number) {
|
||||
this.model.resend(number);
|
||||
}.bind(this));
|
||||
},
|
||||
select: function(e) {
|
||||
this.$el.trigger('select', {message: this.model});
|
||||
e.stopPropagation();
|
||||
|
@ -63,6 +85,11 @@
|
|||
} else {
|
||||
this.$el.removeClass('error');
|
||||
}
|
||||
if (this.model.hasNetworkError()) {
|
||||
this.$('.meta').prepend(new NetworkErrorView().render().el);
|
||||
} else {
|
||||
this.$('.meta .hasRetry').remove();
|
||||
}
|
||||
},
|
||||
renderControl: function() {
|
||||
if (this.model.isEndSession() || this.model.isGroupUpdate()) {
|
||||
|
@ -79,7 +106,7 @@
|
|||
message: this.model.get('body'),
|
||||
timestamp: this.model.get('sent_at'),
|
||||
sender: (contact && contact.getTitle()) || '',
|
||||
avatar: (contact && contact.getAvatar())
|
||||
avatar: (contact && contact.getAvatar()),
|
||||
}, this.render_partials())
|
||||
);
|
||||
this.timeStampView.setElement(this.$('.timestamp'));
|
||||
|
|
|
@ -70,8 +70,7 @@
|
|||
}
|
||||
|
||||
.message-detail {
|
||||
.key-conflict-dialogue,
|
||||
.hasRetry {
|
||||
.key-conflict-dialogue {
|
||||
background: #F3F3A7;
|
||||
border-radius: 5px;
|
||||
padding: 1em;
|
||||
|
@ -92,24 +91,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.hasRetry {
|
||||
padding: 10px 20px;
|
||||
button {
|
||||
margin: 5px;
|
||||
background: $blue;
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: url('/images/refresh.png') no-repeat center center;
|
||||
background-size: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.key-conflict-dialogue {
|
||||
.content p {
|
||||
max-width: 40em;
|
||||
|
@ -247,7 +228,6 @@
|
|||
}
|
||||
|
||||
.timestamp {
|
||||
font-size: smaller;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
|
@ -300,28 +280,43 @@
|
|||
}
|
||||
|
||||
.meta {
|
||||
font-size: smaller;
|
||||
margin-top: 3px;
|
||||
float: right;
|
||||
cursor: pointer;
|
||||
|
||||
.timestamp, .status {
|
||||
opacity: 0.5;
|
||||
.hasRetry + .timestamp {
|
||||
&:before {
|
||||
content:"\00b7"; // ·
|
||||
font-weight: bold;
|
||||
padding: 0 5px 0 4px;
|
||||
text-decoration: none;
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.timestamp, .status {
|
||||
.retry {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.hasRetry, .timestamp, .status {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.timestamp, .status {
|
||||
cursor: pointer;
|
||||
opacity: 0.5;
|
||||
|
||||
&:hover {
|
||||
opacity: 1.0;
|
||||
}
|
||||
.timestamp {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.status {
|
||||
float: right;
|
||||
width: 18px;
|
||||
height: 1em;
|
||||
height: 14px;
|
||||
line-height: 1em;
|
||||
}
|
||||
.sent .status {
|
||||
display: inline-block;
|
||||
|
|
|
@ -675,14 +675,12 @@ input.search {
|
|||
.key-verification .placeholder {
|
||||
font-weight: bold; }
|
||||
|
||||
.message-detail .key-conflict-dialogue,
|
||||
.message-detail .hasRetry {
|
||||
.message-detail .key-conflict-dialogue {
|
||||
background: #F3F3A7;
|
||||
border-radius: 5px;
|
||||
padding: 1em;
|
||||
margin: 1em; }
|
||||
.message-detail .key-conflict-dialogue button,
|
||||
.message-detail .hasRetry button {
|
||||
.message-detail .key-conflict-dialogue button {
|
||||
outline: none;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
|
@ -690,22 +688,8 @@ input.search {
|
|||
padding: 0.5em 1em;
|
||||
font-weight: bold;
|
||||
line-height: 18px; }
|
||||
.message-detail .key-conflict-dialogue button span,
|
||||
.message-detail .hasRetry button span {
|
||||
.message-detail .key-conflict-dialogue button span {
|
||||
vertical-align: middle; }
|
||||
.message-detail .hasRetry {
|
||||
padding: 10px 20px; }
|
||||
.message-detail .hasRetry button {
|
||||
margin: 5px;
|
||||
background: #2090ea; }
|
||||
.message-detail .hasRetry button:before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: url("/images/refresh.png") no-repeat center center;
|
||||
background-size: 100%; }
|
||||
.message-detail .key-conflict-dialogue .content p {
|
||||
max-width: 40em;
|
||||
margin: 1em auto; }
|
||||
|
@ -807,7 +791,6 @@ input.search {
|
|||
font-weight: bold; }
|
||||
|
||||
.timestamp {
|
||||
font-size: smaller;
|
||||
margin-right: 3px; }
|
||||
|
||||
.message-container,
|
||||
|
@ -853,25 +836,39 @@ input.search {
|
|||
margin: 0; }
|
||||
.message-container .meta,
|
||||
.message-list .meta {
|
||||
font-size: smaller;
|
||||
margin-top: 3px;
|
||||
float: right;
|
||||
cursor: pointer; }
|
||||
float: right; }
|
||||
.message-container .meta .hasRetry + .timestamp:before,
|
||||
.message-list .meta .hasRetry + .timestamp:before {
|
||||
content: "\00b7";
|
||||
font-weight: bold;
|
||||
padding: 0 5px 0 4px;
|
||||
text-decoration: none;
|
||||
opacity: 0.5; }
|
||||
.message-container .meta .retry,
|
||||
.message-list .meta .retry {
|
||||
text-decoration: underline;
|
||||
cursor: pointer; }
|
||||
.message-container .meta .hasRetry, .message-container .meta .timestamp, .message-container .meta .status,
|
||||
.message-list .meta .hasRetry,
|
||||
.message-list .meta .timestamp,
|
||||
.message-list .meta .status {
|
||||
float: left; }
|
||||
.message-container .meta .timestamp, .message-container .meta .status,
|
||||
.message-list .meta .timestamp,
|
||||
.message-list .meta .status {
|
||||
cursor: pointer;
|
||||
opacity: 0.5; }
|
||||
.message-container .meta:hover .timestamp, .message-container .meta:hover .status,
|
||||
.message-list .meta:hover .timestamp,
|
||||
.message-list .meta:hover .status {
|
||||
opacity: 1.0; }
|
||||
.message-container .meta:hover .timestamp,
|
||||
.message-list .meta:hover .timestamp {
|
||||
text-decoration: underline; }
|
||||
.message-container .meta .timestamp:hover, .message-container .meta .status:hover,
|
||||
.message-list .meta .timestamp:hover,
|
||||
.message-list .meta .status:hover {
|
||||
opacity: 1.0; }
|
||||
.message-container .status,
|
||||
.message-list .status {
|
||||
float: right;
|
||||
width: 18px;
|
||||
height: 1em; }
|
||||
height: 14px;
|
||||
line-height: 1em; }
|
||||
.message-container .sent .status,
|
||||
.message-list .sent .status {
|
||||
display: inline-block;
|
||||
|
|
Loading…
Reference in a new issue