Merge remote-tracking branch 'origin/master'

This commit is contained in:
Weblate 2017-11-17 12:59:13 +01:00
commit d0d5f7c800
5 changed files with 112 additions and 96 deletions

View File

@ -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)

View File

@ -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 @@
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 @@
} }
}); });
_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 @@
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 @@
} }
}, },
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 @@
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);

View File

@ -1 +0,0 @@
<canvas height="{{o.height}}px" width="{{o.width}}px" class="avatar"></canvas>

View File

@ -1,17 +1,4 @@
<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 @@
<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>
{[ } ]} {[ } ]}

View File

@ -0,0 +1,14 @@
<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>