Prechádzať zdrojové kódy

New "getOccupantActionButtons" hook, so that plugins can add actions on MUC occupants. (#3475)

* New "getOccupantActionButtons" hook, so that plugins can add actions on MUC occupants.

* Occupant actions: move it to the right.

* Code review.

* Accessibility.
John Livingston 11 mesiacov pred
rodič
commit
ae01a08b1a

+ 1 - 0
CHANGES.md

@@ -35,6 +35,7 @@
 - Upgrade to Bootstrap 5
 - Add a new theme 'Cyberpunk' and remove the old 'Concord' theme.
 - Improved accessibility.
+- New "getOccupantActionButtons" hook, so that plugins can add actions on MUC occupants.
 
 ### Breaking changes:
 

+ 1 - 1
src/plugins/muc-views/sidebar.js

@@ -55,7 +55,7 @@ export default class MUCSidebar extends CustomElement {
         const tpl = tplMUCSidebar(this, Object.assign(
             this.model.toJSON(), {
                 'occupants': [...this.model.occupants.models],
-                'onOccupantClicked': ev => this.onOccupantClicked(ev),
+                'onOccupantClicked': ev => this.onOccupantClicked(ev)
             }
         ));
         return tpl;

+ 15 - 2
src/plugins/muc-views/styles/muc-occupants.scss

@@ -109,19 +109,32 @@
                             .occupant-nick-badge {
                                 display: flex;
                                 justify-content: space-between;
-                                flex-wrap: wrap;
+                                flex-wrap: nowrap;
+                                align-items: center;
+                                gap: 0.25rem;
+
+                                .occupant-nick {
+                                    flex-grow: 2;
+                                }
 
                                 .occupant-badges {
                                     display: flex;
                                     justify-content: flex-end;
                                     flex-wrap: wrap;
                                     flex-direction: row;
+                                    flex-shrink: 1;
+                                    gap: 0.25rem;
 
                                     span {
                                         height: 1.6em;
-                                        margin-right: 0.25rem;
                                     }
                                 }
+
+                                .occupant-actions {
+                                    // We must specify the position, else there is a bug:
+                                    // clicking on an action would close the dropdown without triggering the action.
+                                    position: static;
+                                }
                             }
 
                             div.row.g-0{

+ 44 - 0
src/plugins/muc-views/templates/occupant.js

@@ -1,9 +1,11 @@
 /**
  * @typedef {import('@converse/headless').MUCOccupant} MUCOccupant
  */
+import { api } from '@converse/headless';
 import { PRETTY_CHAT_STATUS } from '../constants.js';
 import { __ } from 'i18n';
 import { html } from "lit";
+import { until } from 'lit/directives/until.js';
 import { showOccupantModal } from '../utils.js';
 import { getAuthorStyle } from 'utils/color.js';
 
@@ -29,6 +31,45 @@ const occupant_title = /** @param {MUCOccupant} o */(o) => {
     }
 }
 
+/**
+ * @param {MUCOccupant} o
+ */
+async function tplActionButtons (o) {
+    /**
+     * *Hook* which allows plugins to add action buttons on occupants
+     * @event _converse#getOccupantActionButtons
+     * @example
+     *  api.listen.on('getOccupantActionButtons', (el, buttons) => {
+     *      buttons.push({
+     *          'i18n_text': 'Foo',
+     *          'handler': ev => alert('Foo!'),
+     *          'button_class': 'chat-occupant__action-foo',
+     *          'icon_class': 'fa fa-check',
+     *          'name': 'foo'
+     *      });
+     *      return buttons;
+     *  });
+     */
+    const buttons = await api.hook('getOccupantActionButtons', o, []);
+    if (!buttons?.length) { return '' }
+
+    const items = buttons.map(b => {
+        return html`
+        <button class="dropdown-item ${b.button_class}" @click=${b.handler} type="button">
+            <converse-icon
+                class="${b.icon_class}"
+                color="var(--inverse-link-color)"
+                size="1em"
+                aria-hidden="true"
+            ></converse-icon>&nbsp;${b.i18n_text}
+        </button>`
+    });
+
+    return html`<converse-dropdown
+        class="occupant-actions chatbox-btn"
+        .items=${items}
+    ></converse-dropdown>`;
+}
 
 /**
  * @param {MUCOccupant} o
@@ -87,6 +128,9 @@ export default (o, chat) => {
                         ${ (role === "moderator") ? html`<span class="badge badge-info">${i18n_moderator}</span>` : '' }
                         ${ (role === "visitor") ? html`<span class="badge badge-secondary">${i18n_visitor}</span>`  : '' }
                     </span>
+                    ${
+                        until(tplActionButtons(o))
+                    }
                 </div>
             </div>
         </li>