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)
- 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.
- In the chat heading, two avatars sometimes get rendered.
- Refetch the roster from the server after reconnection.
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)

View File

@ -14,13 +14,13 @@
"emojione",
"xss",
"tpl!chatbox",
"tpl!chatbox_head",
"tpl!new_day",
"tpl!action",
"tpl!emojis",
"tpl!message",
"tpl!help_message",
"tpl!toolbar",
"tpl!avatar",
"tpl!spinner"
], factory);
}(this, function (
@ -30,13 +30,13 @@
emojione,
xss,
tpl_chatbox,
tpl_chatbox_head,
tpl_new_day,
tpl_action,
tpl_emojis,
tpl_message,
tpl_help_message,
tpl_toolbar,
tpl_avatar,
tpl_spinner
) {
"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({
length: 200,
tagName: 'div',
className: 'chatbox hidden',
is_chatroom: false, // Leaky abstraction from MUC
@ -237,43 +296,47 @@
initialize () {
this.markScrolled = _.debounce(this.markScrolled, 100);
this.createEmojiPicker();
this.model.messages.on('add', this.onMessageAdded, 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
this.model.on('change:chat_state', this.sendChatState, 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('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);
},
render () {
this.$el.attr('id', this.model.get('box_id'))
.html(tpl_chatbox(
_.extend(this.model.toJSON(), {
show_toolbar: _converse.show_toolbar,
show_textarea: true,
show_send_button: _converse.show_send_button,
title: this.model.get('fullname'),
unread_msgs: __('You have unread messages'),
info_close: __('Close this chat box'),
label_personal_message: __('Personal message'),
label_send: __('Send')
}
)
)
);
this.el.setAttribute('id', this.model.get('box_id'));
this.el.innerHTML = tpl_chatbox(
_.extend(this.model.toJSON(), {
show_toolbar: _converse.show_toolbar,
show_textarea: true,
show_send_button: _converse.show_send_button,
unread_msgs: __('You have unread messages'),
label_personal_message: __('Personal message'),
label_send: __('Send')
}
)
);
this.$content = this.$el.find('.chat-content');
this.renderToolbar().renderAvatar();
_converse.emit('chatBoxOpened', this);
utils.refreshWebkit();
return this.showStatusMessage();
return this;
},
insertHeading () {
const flyout = this.el.querySelector('.flyout');
flyout.insertBefore(this.heading.el, flyout.querySelector('.chat-body'));
return this;
},
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) {
if (ev && ev.preventDefault) { ev.preventDefault(); }
if (Backbone.history.getFragment() === "converse/chat?jid="+this.model.get('jid')) {
@ -879,37 +926,6 @@
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 () {
this.el.querySelector('.chat-textarea').focus();
_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="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-content {[ if (o.show_send_button) { ]}chat-content-sendbutton{[ } ]}"></div>
<div class="new-msgs-indicator hidden">▼ {{{ o.unread_msgs }}} ▼</div>
@ -20,14 +7,13 @@
{[ if (o.show_toolbar) { ]}
<ul class="chat-toolbar no-text-select"></ul>
{[ } ]}
<textarea
type="text"
class="chat-textarea {[ if (o.show_send_button) { ]}chat-textarea-send-button{[ } ]}"
placeholder="{{{o.label_personal_message}}}"/>
{[ if (o.show_send_button) { ]}
<button type="submit" class="pure-button send-button">{{{ o.label_send }}}</button>
{[ } ]}
<textarea
type="text"
class="chat-textarea {[ if (o.show_send_button) { ]}chat-textarea-send-button{[ } ]}"
placeholder="{{{o.label_personal_message}}}"></textarea>
{[ if (o.show_send_button) { ]}
<button type="submit" class="pure-button send-button">{{{ o.label_send }}}</button>
{[ } ]}
</form>
{[ } ]}
</div>

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>