Commit bac1d222 authored by JC Brand's avatar JC Brand

Fix: In chatbox heading two avatars sometimes get rendered

parent 250b0647
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
- #949 Don't flash the roster contacts filter (i.e. hide by default) - #949 Don't flash the roster contacts filter (i.e. hide by default)
- Don't require `auto_login` to be `true` when using the API to log in. - Don't require `auto_login` to be `true` when using the API to log in.
- Moment locale wasn't being set to the value passed via the `i18n` option. - Moment locale wasn't being set to the value passed via the `i18n` option.
- In the chat heading, two avatars sometimes get rendered.
- Refetch the roster from the server after reconnection. - Refetch the roster from the server after reconnection.
From the perspective of the XMPP server, this is an entirely new login, From the perspective of the XMPP server, this is an entirely new login,
and therefore as per [RFC-6121](https://tools.ietf.org/html/rfc6121#section-2.1.6) and therefore as per [RFC-6121](https://tools.ietf.org/html/rfc6121#section-2.1.6)
......
...@@ -14,13 +14,13 @@ ...@@ -14,13 +14,13 @@
"emojione", "emojione",
"xss", "xss",
"tpl!chatbox", "tpl!chatbox",
"tpl!chatbox_head",
"tpl!new_day", "tpl!new_day",
"tpl!action", "tpl!action",
"tpl!emojis", "tpl!emojis",
"tpl!message", "tpl!message",
"tpl!help_message", "tpl!help_message",
"tpl!toolbar", "tpl!toolbar",
"tpl!avatar",
"tpl!spinner" "tpl!spinner"
], factory); ], factory);
}(this, function ( }(this, function (
...@@ -30,13 +30,13 @@ ...@@ -30,13 +30,13 @@
emojione, emojione,
xss, xss,
tpl_chatbox, tpl_chatbox,
tpl_chatbox_head,
tpl_new_day, tpl_new_day,
tpl_action, tpl_action,
tpl_emojis, tpl_emojis,
tpl_message, tpl_message,
tpl_help_message, tpl_help_message,
tpl_toolbar, tpl_toolbar,
tpl_avatar,
tpl_spinner tpl_spinner
) { ) {
"use strict"; "use strict";
...@@ -218,9 +218,68 @@ ...@@ -218,9 +218,68 @@
} }
}); });
_converse.ChatBoxHeading = Backbone.VDOMView.extend({
initialize () {
this.model.on('change:image', this.setAvatar, this);
this.model.on('change:status', this.onStatusMessageChanged, this);
this.model.on('change:fullname', this.render, this);
this.initializeAvatar();
},
renderHTML () {
return tpl_chatbox_head(
_.extend(this.model.toJSON(), {
'avatar_width': _converse.chatview_avatar_width,
'avatar_height': _converse.chatview_avatar_height,
'info_close': __('Close this chat box'),
})
);
},
afterRender () {
this.setAvatar();
},
setAvatar () {
this.avatar.src = `data:${this.model.get('image_type')};base64,${this.model.get('image')}`;
},
initializeAvatar () {
var that = this;
this.avatar = new Image();
this.avatar.onload = function () {
const canvas = that.el.querySelector('canvas');
const avatar_width = _converse.chatview_avatar_width;
const avatar_height = _converse.chatview_avatar_height;
// XXX: this seems to be needed to work around the
// chrome setting width/height to 0 (possible due to
// no canvas data being there?)
canvas.setAttribute('width', avatar_width);
canvas.setAttribute('height', avatar_height);
const ctx = canvas.getContext('2d');
const ratio = this.width/this.height;
if (ratio < 1) {
ctx.drawImage(this, 0,0, avatar_width, avatar_height*(1/ratio));
} else {
ctx.drawImage(this, 0,0, avatar_width, avatar_height*ratio);
}
};
},
onStatusMessageChanged (item) {
this.render();
_converse.emit('contactStatusMessageChanged', {
'contact': item.attributes,
'message': item.get('status')
});
}
});
_converse.ChatBoxView = Backbone.View.extend({ _converse.ChatBoxView = Backbone.View.extend({
length: 200, length: 200,
tagName: 'div',
className: 'chatbox hidden', className: 'chatbox hidden',
is_chatroom: false, // Leaky abstraction from MUC is_chatroom: false, // Leaky abstraction from MUC
...@@ -237,43 +296,47 @@ ...@@ -237,43 +296,47 @@
initialize () { initialize () {
this.markScrolled = _.debounce(this.markScrolled, 100); this.markScrolled = _.debounce(this.markScrolled, 100);
this.createEmojiPicker(); this.createEmojiPicker();
this.model.messages.on('add', this.onMessageAdded, this); this.model.messages.on('add', this.onMessageAdded, this);
this.model.on('show', this.show, this); this.model.on('show', this.show, this);
this.model.on('destroy', this.hide, this); this.model.on('destroy', this.remove, this);
// TODO check for changed fullname as well // TODO check for changed fullname as well
this.model.on('change:chat_state', this.sendChatState, this); this.model.on('change:chat_state', this.sendChatState, this);
this.model.on('change:chat_status', this.onChatStatusChanged, this); this.model.on('change:chat_status', this.onChatStatusChanged, this);
this.model.on('change:image', this.renderAvatar, this);
this.model.on('change:status', this.onStatusChanged, this);
this.model.on('showHelpMessages', this.showHelpMessages, this); this.model.on('showHelpMessages', this.showHelpMessages, this);
this.model.on('sendMessage', this.sendMessage, this); this.model.on('sendMessage', this.sendMessage, this);
this.render().fetchMessages();
this.heading = new _converse.ChatBoxHeading({'model': this.model});
this.heading.render();
this.heading.chatview = this;
this.render().renderToolbar().insertHeading().fetchMessages();
utils.refreshWebkit();
_converse.emit('chatBoxOpened', this);
_converse.emit('chatBoxInitialized', this); _converse.emit('chatBoxInitialized', this);
}, },
render () { render () {
this.$el.attr('id', this.model.get('box_id')) this.el.setAttribute('id', this.model.get('box_id'));
.html(tpl_chatbox( this.el.innerHTML = tpl_chatbox(
_.extend(this.model.toJSON(), { _.extend(this.model.toJSON(), {
show_toolbar: _converse.show_toolbar, show_toolbar: _converse.show_toolbar,
show_textarea: true, show_textarea: true,
show_send_button: _converse.show_send_button, show_send_button: _converse.show_send_button,
title: this.model.get('fullname'),
unread_msgs: __('You have unread messages'), unread_msgs: __('You have unread messages'),
info_close: __('Close this chat box'),
label_personal_message: __('Personal message'), label_personal_message: __('Personal message'),
label_send: __('Send') label_send: __('Send')
} }
) )
)
); );
this.$content = this.$el.find('.chat-content'); this.$content = this.$el.find('.chat-content');
this.renderToolbar().renderAvatar(); return this;
_converse.emit('chatBoxOpened', this); },
utils.refreshWebkit();
return this.showStatusMessage(); insertHeading () {
const flyout = this.el.querySelector('.flyout');
flyout.insertBefore(this.heading.el, flyout.querySelector('.chat-body'));
return this;
}, },
createEmojiPicker () { createEmojiPicker () {
...@@ -816,22 +879,6 @@ ...@@ -816,22 +879,6 @@
} }
}, },
onStatusChanged (item) {
this.showStatusMessage();
_converse.emit('contactStatusMessageChanged', {
'contact': item.attributes,
'message': item.get('status')
});
},
showStatusMessage (msg) {
msg = msg || this.model.get('status');
if (_.isString(msg)) {
this.$el.find('p.user-custom-message').text(msg).attr('title', msg);
}
return this;
},
close (ev) { close (ev) {
if (ev && ev.preventDefault) { ev.preventDefault(); } if (ev && ev.preventDefault) { ev.preventDefault(); }
if (Backbone.history.getFragment() === "converse/chat?jid="+this.model.get('jid')) { if (Backbone.history.getFragment() === "converse/chat?jid="+this.model.get('jid')) {
...@@ -879,37 +926,6 @@ ...@@ -879,37 +926,6 @@
return this; return this;
}, },
renderAvatar () {
if (!this.model.get('image')) {
return;
}
const width = _converse.chatview_avatar_width;
const height = _converse.chatview_avatar_height;
const img_src = `data:${this.model.get('image_type')};base64,${this.model.get('image')}`,
canvas = $(tpl_avatar({
'width': width,
'height': height
})).get(0);
if (!(canvas.getContext && canvas.getContext('2d'))) {
return this;
}
const ctx = canvas.getContext('2d');
const img = new Image(); // Create new Image object
img.onload = function () {
const ratio = img.width/img.height;
if (ratio < 1) {
ctx.drawImage(img, 0,0, width, height*(1/ratio));
} else {
ctx.drawImage(img, 0,0, width, height*ratio);
}
};
img.src = img_src;
this.$el.find('.chat-title').before(canvas);
return this;
},
focus () { focus () {
this.el.querySelector('.chat-textarea').focus(); this.el.querySelector('.chat-textarea').focus();
_converse.emit('chatBoxFocused', this); _converse.emit('chatBoxFocused', this);
......
<canvas height="{{o.height}}px" width="{{o.width}}px" class="avatar"></canvas>
<div class="flyout box-flyout"> <div class="flyout box-flyout">
<div class="chat-head chat-head-chatbox">
<a class="chatbox-btn close-chatbox-button icon-close" title="{{{o.info_close}}}"></a>
<div class="chat-title">
{[ if (o.url) { ]}
<a href="{{{o.url}}}" target="_blank" rel="noopener" class="user">
{[ } ]}
{{{ o.title }}}
{[ if (o.url) { ]}
</a>
{[ } ]}
<p class="user-custom-message"><p/>
</div>
</div>
<div class="chat-body"> <div class="chat-body">
<div class="chat-content {[ if (o.show_send_button) { ]}chat-content-sendbutton{[ } ]}"></div> <div class="chat-content {[ if (o.show_send_button) { ]}chat-content-sendbutton{[ } ]}"></div>
<div class="new-msgs-indicator hidden">▼ {{{ o.unread_msgs }}} ▼</div> <div class="new-msgs-indicator hidden">▼ {{{ o.unread_msgs }}} ▼</div>
...@@ -23,8 +10,7 @@ ...@@ -23,8 +10,7 @@
<textarea <textarea
type="text" type="text"
class="chat-textarea {[ if (o.show_send_button) { ]}chat-textarea-send-button{[ } ]}" class="chat-textarea {[ if (o.show_send_button) { ]}chat-textarea-send-button{[ } ]}"
placeholder="{{{o.label_personal_message}}}"/> placeholder="{{{o.label_personal_message}}}"></textarea>
{[ if (o.show_send_button) { ]} {[ if (o.show_send_button) { ]}
<button type="submit" class="pure-button send-button">{{{ o.label_send }}}</button> <button type="submit" class="pure-button send-button">{{{ o.label_send }}}</button>
{[ } ]} {[ } ]}
......
<div class="chat-head chat-head-chatbox">
<a class="chatbox-btn close-chatbox-button icon-close" title="{{{o.info_close}}}"></a>
<canvas height="{{{o.avatar_height}}}px" width="{{{o.avatar_width}}}px" class="avatar"></canvas>
<div class="chat-title">
{[ if (o.url) { ]}
<a href="{{{o.url}}}" target="_blank" rel="noopener" class="user">
{[ } ]}
{{{ o.fullname }}}
{[ if (o.url) { ]}
</a>
{[ } ]}
<p class="user-custom-message">{{{ o.status }}}</p>
</div>
</div>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment