Browse Source

Use Lit for bottom panel elements

JC Brand 1 year ago
parent
commit
d5e2d89a2f

+ 13 - 19
src/plugins/chatview/bottom-panel.js

@@ -1,51 +1,45 @@
 import './message-form.js';
-import debounce from 'lodash-es/debounce';
 import tplBottomPanel from './templates/bottom-panel.js';
-import ElementView from '@converse/skeletor/src/element.js';
+import { CustomElement } from 'shared/components/element.js';
 import { _converse, api } from '@converse/headless';
 import { clearMessages } from './utils.js';
-import { render } from 'lit';
 
 import './styles/chat-bottom-panel.scss';
 
 
-export default class ChatBottomPanel extends ElementView {
-    events = {
-        'click .send-button': 'sendButtonClicked',
-        'click .toggle-clear': 'clearMessages'
-    };
-
-    constructor () {
-        super();
-        this.debouncedRender = debounce(this.render, 100);
-    }
+export default class ChatBottomPanel extends CustomElement {
 
     async connectedCallback () {
         super.connectedCallback();
         await this.initialize();
-        this.render(); // don't call in initialize, since the MUCBottomPanel subclasses it
-                       // and we want to render after it has finished as wel.
+        // Don't call in initialize, since the MUCBottomPanel subclasses it
+        // and we want to render after it has finished as well.
+        this.requestUpdate();
     }
 
     async initialize () {
         this.model = await api.chatboxes.get(this.getAttribute('jid'));
         await this.model.initialized;
-        this.listenTo(this.model, 'change:num_unread', this.debouncedRender)
+        this.listenTo(this.model, 'change:num_unread', () => this.requestUpdate());
         this.listenTo(this.model, 'emoji-picker-autocomplete', this.autocompleteInPicker);
 
         this.addEventListener('focusin', ev => this.emitFocused(ev));
         this.addEventListener('focusout', ev => this.emitBlurred(ev));
+        this.addEventListener('click', ev => this.sendButtonClicked(ev));
     }
 
     render () {
-        render(tplBottomPanel({
+        if (!this.model) return '';
+        return tplBottomPanel({
             'model': this.model,
             'viewUnreadMessages': ev => this.viewUnreadMessages(ev)
-        }), this);
+        });
     }
 
     sendButtonClicked (ev) {
-        this.querySelector('converse-message-form')?.onFormSubmitted(ev);
+        if (ev.delegateTarget?.dataset.action === 'sendMessage') {
+            this.querySelector('converse-message-form')?.onFormSubmitted(ev);
+        }
     }
 
     viewUnreadMessages (ev) {

+ 6 - 7
src/plugins/chatview/message-form.js

@@ -1,5 +1,5 @@
 import tplMessageForm from './templates/message-form.js';
-import ElementView from '@converse/skeletor/src/element.js';
+import { CustomElement } from 'shared/components/element.js';
 import { __ } from 'i18n';
 import { _converse, api, converse } from "@converse/headless";
 import { parseMessageForCommands } from './utils.js';
@@ -8,14 +8,13 @@ import { prefixMentions } from '@converse/headless/utils/index.js';
 const { u } = converse.env;
 
 
-export default class MessageForm extends ElementView {
+export default class MessageForm extends CustomElement {
 
-    async connectedCallback () {
-        super.connectedCallback();
+    async initialize () {
         this.model = _converse.chatboxes.get(this.getAttribute('jid'));
         await this.model.initialized;
         this.listenTo(this.model.messages, 'change:correcting', this.onMessageCorrecting);
-        this.listenTo(this.model, 'change:composing_spoiler', () => this.render());
+        this.listenTo(this.model, 'change:composing_spoiler', () => this.requestUpdate());
 
         this.handleEmojiSelection = ({ detail }) => {
             if (this.model.get('jid') === detail.jid) {
@@ -23,7 +22,7 @@ export default class MessageForm extends ElementView {
             }
         }
         document.addEventListener("emojiSelected", this.handleEmojiSelection);
-        this.render();
+        this.requestUpdate();
     }
 
     disconnectedCallback () {
@@ -31,7 +30,7 @@ export default class MessageForm extends ElementView {
         document.removeEventListener("emojiSelected", this.handleEmojiSelection);
     }
 
-    toHTML () {
+    render () {
         return tplMessageForm(
             Object.assign(this.model.toJSON(), {
                 'onDrop': ev => this.onDrop(ev),

+ 11 - 20
src/plugins/muc-views/bottom-panel.js

@@ -2,51 +2,42 @@ import 'shared/autocomplete/index.js';
 import BottomPanel from 'plugins/chatview/bottom-panel.js';
 import tplMUCBottomPanel from './templates/muc-bottom-panel.js';
 import { _converse, api, converse } from "@converse/headless";
-import { render } from 'lit';
 
 import './styles/muc-bottom-panel.scss';
 
 
 export default class MUCBottomPanel extends BottomPanel {
 
-    events = {
-        'click .hide-occupants': 'hideOccupants',
-        'click .send-button': 'sendButtonClicked',
-    }
-
     async initialize () {
         await super.initialize();
-        this.listenTo(this.model, 'change:hidden_occupants', this.debouncedRender);
-        this.listenTo(this.model, 'change:num_unread_general', this.debouncedRender)
-        this.listenTo(this.model.features, 'change:moderated', this.debouncedRender);
+        this.listenTo(this.model, 'change:hidden_occupants', () => this.requestUpdate());
+        this.listenTo(this.model, 'change:num_unread_general', () => this.requestUpdate())
+        this.listenTo(this.model.features, 'change:moderated', () => this.requestUpdate());
         this.listenTo(this.model.occupants, 'add', this.renderIfOwnOccupant)
         this.listenTo(this.model.occupants, 'change:role', this.renderIfOwnOccupant);
-        this.listenTo(this.model.session, 'change:connection_status', this.debouncedRender);
+        this.listenTo(this.model.session, 'change:connection_status', () => this.requestUpdate());
     }
 
     render () {
+        if (!this.model) return '';
         const entered = this.model.session.get('connection_status') === converse.ROOMSTATUS.ENTERED;
         const can_edit = entered && !(this.model.features.get('moderated') && this.model.getOwnRole() === 'visitor');
-        render(tplMUCBottomPanel({
+        return tplMUCBottomPanel({
             can_edit, entered,
             'model': this.model,
             'is_groupchat': true,
             'viewUnreadMessages': ev => this.viewUnreadMessages(ev)
-        }), this);
+        });
     }
 
     renderIfOwnOccupant (o) {
-        (o.get('jid') === _converse.bare_jid) && this.debouncedRender();
+        (o.get('jid') === _converse.bare_jid) && this.requestUpdate();
     }
 
     sendButtonClicked (ev) {
-        this.querySelector('converse-muc-message-form')?.onFormSubmitted(ev);
-    }
-
-    hideOccupants (ev) {
-        ev?.preventDefault?.();
-        ev?.stopPropagation?.();
-        this.model.save({ 'hidden_occupants': true });
+        if (ev.delegateTarget?.dataset.action === 'sendMessage') {
+            this.querySelector('converse-muc-message-form')?.onFormSubmitted(ev);
+        }
     }
 }
 

+ 14 - 10
src/plugins/muc-views/message-form.js

@@ -6,12 +6,13 @@ import { getAutoCompleteListItem } from './utils.js';
 
 export default class MUCMessageForm extends MessageForm {
 
-    async connectedCallback () {
-        super.connectedCallback();
+    async initialize() {
+        super.initialize();
         await this.model.initialized;
+        this.initMentionAutoComplete();
     }
 
-    toHTML () {
+    render () {
         return tplMUCMessageForm(
             Object.assign(this.model.toJSON(), {
                 'hint_value': this.querySelector('.spoiler-hint')?.value,
@@ -26,12 +27,9 @@ export default class MUCMessageForm extends MessageForm {
             }));
     }
 
-    afterRender () {
+    shouldAutoComplete () {
         const entered = this.model.session.get('connection_status') === converse.ROOMSTATUS.ENTERED;
-        const can_edit = entered && !(this.model.features.get('moderated') && this.model.getOwnRole() === 'visitor');
-        if (entered && can_edit) {
-            this.initMentionAutoComplete();
-        }
+        return entered && !(this.model.features.get('moderated') && this.model.getOwnRole() === 'visitor');
     }
 
     initMentionAutoComplete () {
@@ -56,15 +54,21 @@ export default class MUCMessageForm extends MessageForm {
         return this.model.getAllKnownNicknames().map(nick => ({ 'label': nick, 'value': `@${nick}` }));
     }
 
+    /**
+     * @param {Event} ev
+     */
     onKeyDown (ev) {
-        if (this.mention_auto_complete.onKeyDown(ev)) {
+        if (this.shouldAutoComplete() && this.mention_auto_complete.onKeyDown(ev)) {
             return;
         }
         super.onKeyDown(ev);
     }
 
+    /**
+     * @param {Event} ev
+     */
     onKeyUp (ev) {
-        this.mention_auto_complete.evaluate(ev);
+        if (this.shouldAutoComplete()) this.mention_auto_complete.evaluate(ev);
         super.onKeyUp(ev);
     }
 }

+ 1 - 1
src/shared/chat/templates/toolbar.js

@@ -4,7 +4,7 @@ import { until } from 'lit/directives/until.js';
 
 function tplSendButton () {
     const i18n_send_message = __('Send the message');
-    return html`<button type="submit" class="btn send-button" title="${ i18n_send_message }">
+    return html`<button type="submit" class="btn send-button" data-action="sendMessage" title="${ i18n_send_message }">
         <converse-icon color="var(--toolbar-btn-text-color)" class="fa fa-paper-plane" size="1em"></converse-icon>
     </button>`
 }

+ 5 - 1
src/shared/components/element.js

@@ -9,9 +9,13 @@ export class CustomElement extends LitElement {
         return this;
     }
 
+    initialize () {
+        return null;
+    }
+
     connectedCallback () {
         super.connectedCallback();
-        this.initialize?.();
+        return this.initialize();
     }
 
     disconnectedCallback () {