Browse Source

Fix: In chatbox heading two avatars sometimes get rendered

JC Brand 7 years ago
parent
commit
bac1d22205
5 changed files with 112 additions and 96 deletions
  1. 1 0
      CHANGES.md
  2. 90 74
      src/converse-chatview.js
  3. 0 1
      src/templates/avatar.html
  4. 7 21
      src/templates/chatbox.html
  5. 14 0
      src/templates/chatbox_head.html

+ 1 - 0
CHANGES.md

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

+ 90 - 74
src/converse-chatview.js

@@ -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'))
-                        .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.$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 () {
                 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);

+ 0 - 1
src/templates/avatar.html

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

+ 7 - 21
src/templates/chatbox.html

@@ -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>
@@ -20,14 +7,13 @@
             {[ if (o.show_toolbar) { ]}
             {[ if (o.show_toolbar) { ]}
                 <ul class="chat-toolbar no-text-select"></ul>
                 <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>
         </form>
         {[ } ]}
         {[ } ]}
     </div>
     </div>

+ 14 - 0
src/templates/chatbox_head.html

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