Explorar o código

Fixes concerning dropdowns

JC Brand %!s(int64=4) %!d(string=hai) anos
pai
achega
73989e09a9

+ 96 - 0
src/shared/chat/emoji-dropdown.js

@@ -0,0 +1,96 @@
+import DropdownBase from "shared/components/dropdown.js";
+import { __ } from 'i18n';
+import { _converse, api, converse } from "@converse/headless/core";
+import { html } from "lit";
+import { initStorage } from '@converse/headless/shared/utils.js';
+import { until } from 'lit/directives/until.js';
+
+const u = converse.env.utils;
+
+
+export default class EmojiDropdown extends DropdownBase {
+
+    static get properties() {
+        return {
+            chatview: { type: Object }
+        };
+    }
+
+    constructor () {
+        super();
+        // This is an optimization, we lazily render the emoji picker, otherwise tests slow to a crawl.
+        this.render_emojis = false;
+    }
+
+    initModel () {
+        if (!this.init_promise) {
+            this.init_promise = (async () => {
+                await api.emojis.initialize()
+                const id = `converse.emoji-${_converse.bare_jid}-${this.chatview.model.get('jid')}`;
+                this.model = new _converse.EmojiPicker({'id': id});
+                initStorage(this.model, id);
+                await new Promise(resolve => this.model.fetch({'success': resolve, 'error': resolve}));
+                // We never want still be in the autocompleting state upon page load
+                this.model.set({'autocompleting': null, 'ac_position': null});
+            })();
+        }
+        return this.init_promise;
+    }
+
+    render() {
+        return html`
+            <div class="dropup">
+                <button class="toggle-emojis"
+                        title="${__('Insert emojis')}"
+                        data-toggle="dropdown"
+                        aria-haspopup="true"
+                        aria-expanded="false">
+                    <converse-icon
+                        class="fa fa-smile "
+                        path-prefix="${api.settings.get('assets_path')}"
+                        size="1em"></converse-icon>
+                </button>
+                <div class="dropdown-menu">
+                    ${until(this.initModel().then(() => html`
+                        <converse-emoji-picker
+                                .chatview=${this.chatview}
+                                .model=${this.model}
+                                ?render_emojis=${this.render_emojis}
+                                current_category="${this.model.get('current_category') || ''}"
+                                current_skintone="${this.model.get('current_skintone') || ''}"
+                                query="${this.model.get('query') || ''}"
+                        ></converse-emoji-picker>`), '')}
+                </div>
+            </div>`;
+    }
+
+    connectedCallback () {
+        super.connectedCallback();
+        this.render_emojis = false;
+    }
+
+    toggleMenu (ev) {
+        ev.stopPropagation();
+        ev.preventDefault();
+        if (u.hasClass('show', this.menu)) {
+            if (u.ancestor(ev.target, '.toggle-emojis')) {
+                this.hideMenu();
+            }
+        } else {
+            this.showMenu();
+        }
+    }
+
+    async showMenu () {
+        await this.initModel();
+        if (!this.render_emojis) {
+            // Trigger an update so that emojis are rendered
+            this.render_emojis = true;
+            await this.requestUpdate();
+        }
+        super.showMenu();
+        setTimeout(() => this.querySelector('.emoji-search')?.focus());
+    }
+}
+
+api.elements.define('converse-emoji-dropdown', EmojiDropdown);

+ 2 - 92
src/shared/chat/emoji-picker.js

@@ -1,14 +1,10 @@
 import "./emoji-picker-content.js";
+import './emoji-dropdown.js';
 import DOMNavigator from "shared/dom-navigator";
 import debounce from 'lodash-es/debounce';
-import { BaseDropdown } from "shared/components/dropdown.js";
 import { CustomElement } from 'shared/components/element.js';
-import { __ } from 'i18n';
 import { _converse, api, converse } from "@converse/headless/core";
-import { html } from "lit";
-import { initStorage } from '@converse/headless/shared/utils.js';
 import { tpl_emoji_picker } from "./templates/emoji-picker.js";
-import { until } from 'lit/directives/until.js';
 
 import './styles/emoji.scss';
 
@@ -30,6 +26,7 @@ export default class EmojiPicker extends CustomElement {
     }
 
     firstUpdated () {
+        super.firstUpdated();
         this.listenTo(this.model, 'change', o => this.onModelChanged(o.changed));
         this.initArrowNavigation();
     }
@@ -275,91 +272,4 @@ export default class EmojiPicker extends CustomElement {
     }
 }
 
-
-export class EmojiDropdown extends BaseDropdown {
-
-    static get properties() {
-        return {
-            chatview: { type: Object }
-        };
-    }
-
-    constructor () {
-        super();
-        // This is an optimization, we lazily render the emoji picker, otherwise tests slow to a crawl.
-        this.render_emojis = false;
-    }
-
-    initModel () {
-        if (!this.init_promise) {
-            this.init_promise = (async () => {
-                await api.emojis.initialize()
-                const id = `converse.emoji-${_converse.bare_jid}-${this.chatview.model.get('jid')}`;
-                this.model = new _converse.EmojiPicker({'id': id});
-                initStorage(this.model, id);
-                await new Promise(resolve => this.model.fetch({'success': resolve, 'error': resolve}));
-                // We never want still be in the autocompleting state upon page load
-                this.model.set({'autocompleting': null, 'ac_position': null});
-            })();
-        }
-        return this.init_promise;
-    }
-
-    render() {
-        return html`
-            <div class="dropup">
-                <button class="toggle-emojis"
-                        title="${__('Insert emojis')}"
-                        data-toggle="dropdown"
-                        aria-haspopup="true"
-                        aria-expanded="false">
-                    <converse-icon
-                        class="fa fa-smile "
-                        path-prefix="${api.settings.get('assets_path')}"
-                        size="1em"></converse-icon>
-                </button>
-                <div class="dropdown-menu">
-                    ${until(this.initModel().then(() => html`
-                        <converse-emoji-picker
-                                .chatview=${this.chatview}
-                                .model=${this.model}
-                                ?render_emojis=${this.render_emojis}
-                                current_category="${this.model.get('current_category') || ''}"
-                                current_skintone="${this.model.get('current_skintone') || ''}"
-                                query="${this.model.get('query') || ''}"
-                        ></converse-emoji-picker>`), '')}
-                </div>
-            </div>`;
-    }
-
-    connectedCallback () {
-        super.connectedCallback();
-        this.render_emojis = false;
-    }
-
-    toggleMenu (ev) {
-        ev.stopPropagation();
-        ev.preventDefault();
-        if (u.hasClass('show', this.menu)) {
-            if (u.ancestor(ev.target, '.toggle-emojis')) {
-                this.hideMenu();
-            }
-        } else {
-            this.showMenu();
-        }
-    }
-
-    async showMenu () {
-        await this.initModel();
-        if (!this.render_emojis) {
-            // Trigger an update so that emojis are rendered
-            this.render_emojis = true;
-            await this.requestUpdate();
-        }
-        super.showMenu();
-        setTimeout(() => this.querySelector('.emoji-search')?.focus());
-    }
-}
-
-api.elements.define('converse-emoji-dropdown', EmojiDropdown);
 api.elements.define('converse-emoji-picker', EmojiPicker);

+ 9 - 69
src/shared/components/dropdown.js

@@ -1,76 +1,11 @@
 import DOMNavigator from "shared/dom-navigator.js";
-import { CustomElement } from './element.js';
 import { converse, api } from "@converse/headless/core";
 import { html } from 'lit';
 import { until } from 'lit/directives/until.js';
+import DropdownBase from 'shared/components/dropdownbase.js';
 
-const u = converse.env.utils;
 
-
-export class BaseDropdown extends CustomElement {
-
-    connectedCallback() {
-        super.connectedCallback();
-        this.registerEvents();
-    }
-
-    registerEvents() {
-        this.clickOutside = this._clickOutside.bind(this);
-        document.addEventListener('click', this.clickOutside);
-    }
-
-    firstUpdated () {
-        super.firstUpdated();
-        this.initArrowNavigation();
-        this.menu = this.querySelector('.dropdown-menu');
-        this.dropdown = this.firstElementChild;
-        this.button = this.dropdown.querySelector('button');
-        this.dropdown.addEventListener('click', ev => this.toggleMenu(ev));
-        this.dropdown.addEventListener('keyup', ev => this.handleKeyUp(ev));
-    }
-
-    _clickOutside(ev) {
-        if (!this.contains(ev.composedPath()[0])) {
-            this.hideMenu(ev);
-        }
-    }
-
-    hideMenu () {
-        u.removeClass('show', this.menu);
-        this.button?.setAttribute('aria-expanded', false);
-        this.button?.blur();
-    }
-
-    showMenu () {
-        u.addClass('show', this.menu);
-        this.button.setAttribute('aria-expanded', true);
-    }
-
-    toggleMenu (ev) {
-        ev.preventDefault();
-        if (u.hasClass('show', this.menu)) {
-            this.hideMenu();
-        } else {
-            this.showMenu();
-        }
-    }
-
-    handleKeyUp (ev) {
-        if (ev.keyCode === converse.keycodes.ESCAPE) {
-            this.hideMenu();
-        } else if (ev.keyCode === converse.keycodes.DOWN_ARROW && this.navigator && !this.navigator.enabled) {
-            this.enableArrowNavigation(ev);
-        }
-    }
-
-    disconnectedCallback () {
-        document.removeEventListener('click', this.clickOutside);
-        super.disconnectedCallback();
-    }
-}
-
-
-export default class DropdownList extends BaseDropdown {
+export default class Dropdown extends DropdownBase {
 
     static get properties () {
         return {
@@ -93,9 +28,14 @@ export default class DropdownList extends BaseDropdown {
         `;
     }
 
+    firstUpdated () {
+        super.firstUpdated();
+        this.initArrowNavigation();
+    }
+
     hideMenu () {
         super.hideMenu();
-        this.navigator.disable();
+        this.navigator?.disable();
     }
 
     initArrowNavigation () {
@@ -125,4 +65,4 @@ export default class DropdownList extends BaseDropdown {
     }
 }
 
-api.elements.define('converse-dropdown', DropdownList);
+api.elements.define('converse-dropdown', Dropdown);

+ 64 - 0
src/shared/components/dropdownbase.js

@@ -0,0 +1,64 @@
+import { CustomElement } from './element.js';
+import { converse } from "@converse/headless/core";
+
+const u = converse.env.utils;
+
+
+export default class DropdownBase extends CustomElement {
+
+    connectedCallback() {
+        super.connectedCallback();
+        this.registerEvents();
+    }
+
+    registerEvents() {
+        this.clickOutside = (ev) => this._clickOutside(ev);
+        document.addEventListener('click', this.clickOutside);
+    }
+
+    firstUpdated () {
+        super.firstUpdated();
+        this.menu = this.querySelector('.dropdown-menu');
+        this.dropdown = this.firstElementChild;
+        this.button = this.dropdown.querySelector('button');
+        this.dropdown.addEventListener('click', ev => this.toggleMenu(ev));
+        this.dropdown.addEventListener('keyup', ev => this.handleKeyUp(ev));
+    }
+
+    _clickOutside(ev) {
+        if (!this.contains(ev.composedPath()[0])) {
+            this.hideMenu(ev);
+        }
+    }
+
+    hideMenu () {
+        u.removeClass('show', this.menu);
+        this.button?.setAttribute('aria-expanded', false);
+        this.button?.blur();
+    }
+
+    showMenu () {
+        u.addClass('show', this.menu);
+        this.button.setAttribute('aria-expanded', true);
+    }
+
+    toggleMenu (ev) {
+        ev.preventDefault();
+        if (u.hasClass('show', this.menu)) {
+            this.hideMenu();
+        } else {
+            this.showMenu();
+        }
+    }
+
+    handleKeyUp (ev) {
+        if (ev.keyCode === converse.keycodes.ESCAPE) {
+            this.hideMenu();
+        }
+    }
+
+    disconnectedCallback () {
+        document.removeEventListener('click', this.clickOutside);
+        super.disconnectedCallback();
+    }
+}