Просмотр исходного кода

Move more methods from ChatBoxView to shared base class

JC Brand 4 лет назад
Родитель
Сommit
b8d710800a

+ 1 - 0
src/headless/plugins/chat/model.js

@@ -914,6 +914,7 @@ const ChatBox = ModelWithContact.extend({
             return;
         } else {
             u.safeSave(this, {'hidden': false});
+            this.trigger('show');
         }
         return this;
     },

+ 2 - 182
src/plugins/chatview/view.js

@@ -3,11 +3,9 @@ import UserDetailsModal from 'modals/user-details.js';
 import log from '@converse/headless/log';
 import tpl_chatbox from 'templates/chatbox.js';
 import tpl_chatbox_head from 'templates/chatbox_head.js';
-import tpl_spinner from 'templates/spinner.js';
 import { __ } from 'i18n';
 import { _converse, api, converse } from '@converse/headless/core';
-import { debounce } from 'lodash-es';
-import { html, render } from 'lit-html';
+import { render } from 'lit-html';
 
 const u = converse.env.utils;
 const { dayjs } = converse.env;
@@ -71,8 +69,7 @@ export default class ChatView extends BaseChatView {
         this.listenTo(this.model, 'change:show_help_messages', this.renderHelpMessages);
 
         await this.model.messages.fetched;
-        this.model.maybeShow();
-        this.scrollDown();
+        !this.model.get('hidden') && this.afterShown()
         /**
          * Triggered once the {@link _converse.ChatBoxView} has been initialized
          * @event _converse#chatBoxViewInitialized
@@ -82,21 +79,6 @@ export default class ChatView extends BaseChatView {
         api.trigger('chatBoxViewInitialized', this);
     }
 
-    initDebounced () {
-        this.markScrolled = debounce(this._markScrolled, 100);
-        this.debouncedScrollDown = debounce(this.scrollDown, 100);
-
-        // For tests that use Jasmine.Clock we want to turn of
-        // debouncing, since setTimeout breaks.
-        if (api.settings.get('debounced_content_rendering')) {
-            this.renderChatHistory = debounce(() => this.renderChatContent(false), 100);
-            this.renderNotifications = debounce(() => this.renderChatContent(true), 100);
-        } else {
-            this.renderChatHistory = () => this.renderChatContent(false);
-            this.renderNotifications = () => this.renderChatContent(true);
-        }
-    }
-
     render () {
         const result = tpl_chatbox(Object.assign(this.model.toJSON(), { 'markScrolled': ev => this.markScrolled(ev) }));
         render(result, this);
@@ -110,22 +92,6 @@ export default class ChatView extends BaseChatView {
         return this;
     }
 
-    onMessageAdded (message) {
-        this.renderChatHistory();
-
-        if (u.isNewMessage(message)) {
-            if (message.get('sender') === 'me') {
-                // We remove the "scrolled" flag so that the chat area
-                // gets scrolled down. We always want to scroll down
-                // when the user writes a message as opposed to when a
-                // message is received.
-                this.model.set('scrolled', false);
-            } else if (this.model.get('scrolled', true)) {
-                this.showNewMessagesIndicator();
-            }
-        }
-    }
-
     getNotifications () {
         if (this.model.notifications.get('chat_state') === _converse.COMPOSING) {
             return __('%1$s is typing', this.model.getDisplayName());
@@ -147,22 +113,6 @@ export default class ChatView extends BaseChatView {
         ];
     }
 
-    renderHelpMessages () {
-        render(
-            html`
-                <converse-chat-help
-                    .model=${this.model}
-                    .messages=${this.getHelpMessages()}
-                    ?hidden=${!this.model.get('show_help_messages')}
-                    type="info"
-                    chat_type="${this.model.get('type')}"
-                ></converse-chat-help>
-            `,
-
-            this.help_container
-        );
-    }
-
     showControlBox () {
         // Used in mobile view, to navigate back to the controlbox
         _converse.chatboxviews.get('controlbox')?.show();
@@ -285,51 +235,6 @@ export default class ChatView extends BaseChatView {
         }
     }
 
-    /**
-     * Scroll to the previously saved scrollTop position, or scroll
-     * down if it wasn't set.
-     */
-    maintainScrollTop () {
-        const pos = this.model.get('scrollTop');
-        if (pos) {
-            this.msgs_container.scrollTop = pos;
-        } else {
-            this.scrollDown();
-        }
-    }
-
-    addSpinner (append = false) {
-        if (this.querySelector('.spinner') === null) {
-            const el = u.getElementFromTemplateResult(tpl_spinner());
-            if (append) {
-                this.content.insertAdjacentElement('beforeend', el);
-                this.scrollDown();
-            } else {
-                this.content.insertAdjacentElement('afterbegin', el);
-            }
-        }
-    }
-
-    clearSpinner () {
-        this.content.querySelectorAll('.spinner').forEach(u.removeElement);
-    }
-
-    onStatusMessageChanged (item) {
-        this.renderHeading();
-        /**
-         * When a contact's custom status message has changed.
-         * @event _converse#contactStatusMessageChanged
-         * @type {object}
-         * @property { object } contact - The chat buddy
-         * @property { string } message - The message text
-         * @example _converse.api.listen.on('contactStatusMessageChanged', obj => { ... });
-         */
-        api.trigger('contactStatusMessageChanged', {
-            'contact': item.attributes,
-            'message': item.get('status')
-        });
-    }
-
     /**
      * Given a message element, determine wether it should be
      * marked as a followup message to the previous element.
@@ -472,10 +377,6 @@ export default class ChatView extends BaseChatView {
         }
     }
 
-    getOwnMessages () {
-        return this.model.messages.filter({ 'sender': 'me' });
-    }
-
     onEscapePressed (ev) {
         ev.preventDefault();
         const idx = this.model.messages.findLastIndex('correcting');
@@ -506,72 +407,6 @@ export default class ChatView extends BaseChatView {
         }
     }
 
-    onMessageEditButtonClicked (message) {
-        const currently_correcting = this.model.messages.findWhere('correcting');
-        const unsent_text = this.querySelector('.chat-textarea')?.value;
-        if (unsent_text && (!currently_correcting || currently_correcting.get('message') !== unsent_text)) {
-            if (!confirm(__('You have an unsent message which will be lost if you continue. Are you sure?'))) {
-                return;
-            }
-        }
-
-        if (currently_correcting !== message) {
-            currently_correcting?.save('correcting', false);
-            message.save('correcting', true);
-            this.insertIntoTextArea(u.prefixMentions(message), true, true);
-        } else {
-            message.save('correcting', false);
-            this.insertIntoTextArea('', true, false);
-        }
-    }
-
-    editLaterMessage () {
-        let message;
-        let idx = this.model.messages.findLastIndex('correcting');
-        if (idx >= 0) {
-            this.model.messages.at(idx).save('correcting', false);
-            while (idx < this.model.messages.length - 1) {
-                idx += 1;
-                const candidate = this.model.messages.at(idx);
-                if (candidate.get('editable')) {
-                    message = candidate;
-                    break;
-                }
-            }
-        }
-        if (message) {
-            this.insertIntoTextArea(u.prefixMentions(message), true, true);
-            message.save('correcting', true);
-        } else {
-            this.insertIntoTextArea('', true, false);
-        }
-    }
-
-    editEarlierMessage () {
-        let message;
-        let idx = this.model.messages.findLastIndex('correcting');
-        if (idx >= 0) {
-            this.model.messages.at(idx).save('correcting', false);
-            while (idx > 0) {
-                idx -= 1;
-                const candidate = this.model.messages.at(idx);
-                if (candidate.get('editable')) {
-                    message = candidate;
-                    break;
-                }
-            }
-        }
-        message =
-            message ||
-            this.getOwnMessages()
-                .reverse()
-                .find(m => m.get('editable'));
-        if (message) {
-            this.insertIntoTextArea(u.prefixMentions(message), true, true);
-            message.save('correcting', true);
-        }
-    }
-
     inputChanged (ev) { // eslint-disable-line class-methods-use-this
         const height = ev.target.scrollHeight + 'px';
         if (ev.target.style.height != height) {
@@ -580,17 +415,6 @@ export default class ChatView extends BaseChatView {
         }
     }
 
-    async clearMessages (ev) {
-        if (ev && ev.preventDefault) {
-            ev.preventDefault();
-        }
-        const result = confirm(__('Are you sure you want to clear the messages from this conversation?'));
-        if (result === true) {
-            await this.model.clearMessages();
-        }
-        return this;
-    }
-
     onPresenceChanged (item) {
         const show = item.get('show');
         const fullname = this.model.getDisplayName();
@@ -639,10 +463,6 @@ export default class ChatView extends BaseChatView {
         this.maybeFocus();
     }
 
-    showNewMessagesIndicator () {
-        u.showElement(this.querySelector('.new-msgs-indicator'));
-    }
-
     viewUnreadMessages () {
         this.model.save({ 'scrolled': false, 'scrollTop': null });
         this.scrollDown();

+ 3 - 24
src/plugins/controlbox/view.js

@@ -67,10 +67,8 @@ class ControlBoxView extends ElementView {
         }
     }
 
-    async close (ev) {
-        if (ev && ev.preventDefault) {
-            ev.preventDefault();
-        }
+    close (ev) {
+        ev?.preventDefault?.();
         if (
             ev?.name === 'closeAllChatBoxes' &&
             (_converse.disconnection_cause !== _converse.LOGOUT ||
@@ -81,30 +79,11 @@ class ControlBoxView extends ElementView {
         if (api.settings.get('sticky_controlbox')) {
             return;
         }
-        const connection = _converse?.connection || {};
-        if (connection.connected && !connection.disconnecting) {
-            await new Promise((resolve, reject) => {
-                return this.model.save(
-                    { 'closed': true },
-                    { 'success': resolve, 'error': reject, 'wait': true }
-                );
-            });
-        } else {
-            this.model.trigger('hide');
-        }
+        u.safeSave(this.model, { 'closed': true });
         api.trigger('controlBoxClosed', this);
         return this;
     }
 
-    hide () {
-        if (api.settings.get('sticky_controlbox')) {
-            return;
-        }
-        u.addClass('hidden', this);
-        api.trigger('chatBoxClosed', this);
-        return this;
-    }
-
     show () {
         this.model.set('closed', false);
         this.classList.remove('hidden');

+ 163 - 1
src/shared/chatview.js

@@ -1,10 +1,11 @@
+import debounce from 'lodash/debounce';
 import log from '@converse/headless/log';
 import tpl_chatbox_message_form from 'templates/chatbox_message_form.js';
+import tpl_spinner from 'templates/spinner.js';
 import tpl_toolbar from 'templates/toolbar.js';
 import { ElementView } from '@converse/skeletor/src/element.js';
 import { __ } from 'i18n';
 import { _converse, api, converse } from '@converse/headless/core';
-import { debounce } from 'lodash-es';
 import { html, render } from 'lit-html';
 
 const u = converse.env.utils;
@@ -45,6 +46,21 @@ export default class BaseChatView extends ElementView {
         render(this.tpl_chat_content({ messages, 'notifications': this.getNotifications() }), this.msgs_container);
     }
 
+    renderHelpMessages () {
+        render(
+            html`
+                <converse-chat-help
+                    .model=${this.model}
+                    .messages=${this.getHelpMessages()}
+                    ?hidden=${!this.model.get('show_help_messages')}
+                    type="info"
+                    chat_type="${this.model.get('type')}"
+                ></converse-chat-help>
+            `,
+            this.help_container
+        );
+    }
+
     renderMessageForm () {
         const form_container = this.querySelector('.message-form-container');
         render(
@@ -160,6 +176,114 @@ export default class BaseChatView extends ElementView {
         api.trigger('chatBoxFocused', this, ev);
     }
 
+    /**
+     * Scroll to the previously saved scrollTop position, or scroll
+     * down if it wasn't set.
+     */
+    maintainScrollTop () {
+        const pos = this.model.get('scrollTop');
+        if (pos) {
+            this.msgs_container.scrollTop = pos;
+        } else {
+            this.scrollDown();
+        }
+    }
+
+    addSpinner (append = false) {
+        if (this.querySelector('.spinner') === null) {
+            const el = u.getElementFromTemplateResult(tpl_spinner());
+            if (append) {
+                this.content.insertAdjacentElement('beforeend', el);
+                this.scrollDown();
+            } else {
+                this.content.insertAdjacentElement('afterbegin', el);
+            }
+        }
+    }
+
+    clearSpinner () {
+        this.content.querySelectorAll('.spinner').forEach(u.removeElement);
+    }
+
+    onStatusMessageChanged (item) {
+        this.renderHeading();
+        /**
+         * When a contact's custom status message has changed.
+         * @event _converse#contactStatusMessageChanged
+         * @type {object}
+         * @property { object } contact - The chat buddy
+         * @property { string } message - The message text
+         * @example _converse.api.listen.on('contactStatusMessageChanged', obj => { ... });
+         */
+        api.trigger('contactStatusMessageChanged', {
+            'contact': item.attributes,
+            'message': item.get('status')
+        });
+    }
+
+
+    getOwnMessages () {
+        return this.model.messages.filter({ 'sender': 'me' });
+    }
+
+    async clearMessages (ev) {
+        if (ev && ev.preventDefault) {
+            ev.preventDefault();
+        }
+        const result = confirm(__('Are you sure you want to clear the messages from this conversation?'));
+        if (result === true) {
+            await this.model.clearMessages();
+        }
+        return this;
+    }
+
+    editEarlierMessage () {
+        let message;
+        let idx = this.model.messages.findLastIndex('correcting');
+        if (idx >= 0) {
+            this.model.messages.at(idx).save('correcting', false);
+            while (idx > 0) {
+                idx -= 1;
+                const candidate = this.model.messages.at(idx);
+                if (candidate.get('editable')) {
+                    message = candidate;
+                    break;
+                }
+            }
+        }
+        message =
+            message ||
+            this.getOwnMessages()
+                .reverse()
+                .find(m => m.get('editable'));
+        if (message) {
+            this.insertIntoTextArea(u.prefixMentions(message), true, true);
+            message.save('correcting', true);
+        }
+    }
+
+    editLaterMessage () {
+        let message;
+        let idx = this.model.messages.findLastIndex('correcting');
+        if (idx >= 0) {
+            this.model.messages.at(idx).save('correcting', false);
+            while (idx < this.model.messages.length - 1) {
+                idx += 1;
+                const candidate = this.model.messages.at(idx);
+                if (candidate.get('editable')) {
+                    message = candidate;
+                    break;
+                }
+            }
+        }
+        if (message) {
+            this.insertIntoTextArea(u.prefixMentions(message), true, true);
+            message.save('correcting', true);
+        } else {
+            this.insertIntoTextArea('', true, false);
+        }
+    }
+
     async getHeadingDropdownItem (promise_or_data) { // eslint-disable-line class-methods-use-this
         const data = await promise_or_data;
         return html`
@@ -183,6 +307,26 @@ export default class BaseChatView extends ElementView {
         }
     }
 
+    showNewMessagesIndicator () {
+        u.showElement(this.querySelector('.new-msgs-indicator'));
+    }
+
+    onMessageAdded (message) {
+        this.renderChatHistory();
+
+        if (u.isNewMessage(message)) {
+            if (message.get('sender') === 'me') {
+                // We remove the "scrolled" flag so that the chat area
+                // gets scrolled down. We always want to scroll down
+                // when the user writes a message as opposed to when a
+                // message is received.
+                this.model.set('scrolled', false);
+            } else if (this.model.get('scrolled', true)) {
+                this.showNewMessagesIndicator();
+            }
+        }
+    }
+
     onEmojiReceivedFromPicker (emoji) {
         const model = this.querySelector('converse-emoji-picker').model;
         const autocompleting = model.get('autocompleting');
@@ -190,6 +334,24 @@ export default class BaseChatView extends ElementView {
         this.insertIntoTextArea(emoji, autocompleting, false, ac_position);
     }
 
+    onMessageEditButtonClicked (message) {
+        const currently_correcting = this.model.messages.findWhere('correcting');
+        const unsent_text = this.querySelector('.chat-textarea')?.value;
+        if (unsent_text && (!currently_correcting || currently_correcting.get('message') !== unsent_text)) {
+            if (!confirm(__('You have an unsent message which will be lost if you continue. Are you sure?'))) {
+                return;
+            }
+        }
+        if (currently_correcting !== message) {
+            currently_correcting?.save('correcting', false);
+            message.save('correcting', true);
+            this.insertIntoTextArea(u.prefixMentions(message), true, true);
+        } else {
+            message.save('correcting', false);
+            this.insertIntoTextArea('', true, false);
+        }
+    }
+
     /**
      * Insert a particular string value into the textarea of this chat box.
      * @private

+ 1 - 0
src/templates/chatbox_message_form.js

@@ -13,6 +13,7 @@ export default (o) => html`
         <div class="suggestion-box">
             <ul class="suggestion-box__results suggestion-box__results--above" hidden=""></ul>
             <textarea
+                autofocus
                 type="text"
                 class="chat-textarea suggestion-box__input
                     ${ o.show_send_button ? 'chat-textarea-send-button' : '' }