Преглед изворни кода

Occupant view updates

- Add link to open chat from occupant view
- Add dropdown menu
JC Brand пре 8 месеци
родитељ
комит
263cbe3260

+ 32 - 14
src/plugins/muc-views/occupant.js

@@ -1,30 +1,28 @@
 import { Model } from '@converse/skeletor';
 import { Model } from '@converse/skeletor';
-import { _converse, api, converse } from "@converse/headless";
+import { _converse, api, converse } from '@converse/headless';
 import { CustomElement } from 'shared/components/element.js';
 import { CustomElement } from 'shared/components/element.js';
-import tplMUCOccupant from "./templates/muc-occupant.js";
+import tplMUCOccupant from './templates/muc-occupant.js';
 
 
 const { u } = converse.env;
 const { u } = converse.env;
 
 
 import './styles/muc-occupant.scss';
 import './styles/muc-occupant.scss';
 
 
-
 export default class MUCOccupant extends CustomElement {
 export default class MUCOccupant extends CustomElement {
-
-    constructor () {
+    constructor() {
         super();
         super();
         this.muc_jid = null;
         this.muc_jid = null;
         this.occupant_id = null;
         this.occupant_id = null;
     }
     }
 
 
-    static get properties () {
+    static get properties() {
         return {
         return {
             muc_jid: { type: String },
             muc_jid: { type: String },
-            occupant_id: { type: String }
-        }
+            occupant_id: { type: String },
+        };
     }
     }
 
 
     async initialize() {
     async initialize() {
-        super.initialize()
+        super.initialize();
 
 
         const { chatboxes } = _converse.state;
         const { chatboxes } = _converse.state;
         this.muc = chatboxes.get(this.muc_jid);
         this.muc = chatboxes.get(this.muc_jid);
@@ -34,11 +32,28 @@ export default class MUCOccupant extends CustomElement {
         this.requestUpdate();
         this.requestUpdate();
     }
     }
 
 
-    render () {
+    render() {
         return this.muc ? tplMUCOccupant(this) : '';
         return this.muc ? tplMUCOccupant(this) : '';
     }
     }
 
 
-    getVcard () {
+    /**
+     * @param {string} jid
+     */
+    openChat(jid) {
+        api.chats.open(jid, {}, true);
+    }
+
+    closeSidebar() {
+        u.safeSave(this.muc, { 'hidden_occupants': true });
+    }
+
+    /** @param {MouseEvent} [ev] */
+    showOccupantModal(ev) {
+        ev?.preventDefault?.();
+        api.modal.show('converse-muc-occupant-modal', { model: this.model }, ev);
+    }
+
+    getVcard() {
         const model = this.model;
         const model = this.model;
         if (model.vcard) {
         if (model.vcard) {
             return model.vcard;
             return model.vcard;
@@ -47,13 +62,16 @@ export default class MUCOccupant extends CustomElement {
         return jid ? _converse.state.vcards.get(jid) : null;
         return jid ? _converse.state.vcards.get(jid) : null;
     }
     }
 
 
-    addToContacts () {
+    addToContacts() {
         const model = this.model;
         const model = this.model;
         const jid = model.get('jid');
         const jid = model.get('jid');
-        if (jid) api.modal.show('converse-add-contact-modal', {'model': new Model({ jid })});
+        if (jid) api.modal.show('converse-add-contact-modal', { 'model': new Model({ jid }) });
     }
     }
 
 
-    toggleForm (ev) {
+    /**
+     * @param {MouseEvent} ev
+     */
+    toggleForm(ev) {
         const toggle = u.ancestor(ev.target, '.toggle-form');
         const toggle = u.ancestor(ev.target, '.toggle-form');
         const form = toggle.getAttribute('data-form');
         const form = toggle.getAttribute('data-form');
 
 

+ 12 - 0
src/plugins/muc-views/styles/muc-occupant.scss

@@ -3,7 +3,11 @@
         width: 100%;
         width: 100%;
 
 
         .sidebar-heading {
         .sidebar-heading {
+            display: flex;
+            justify-content: space-between;
+            padding: 0.5em;
             padding-top: 0.4em;
             padding-top: 0.4em;
+
             .back-button {
             .back-button {
                 font-size: 0.75em;
                 font-size: 0.75em;
                 padding: 0.5em;
                 padding: 0.5em;
@@ -13,12 +17,20 @@
 
 
         .occupant-details {
         .occupant-details {
             padding-left: 0.3em;
             padding-left: 0.3em;
+            li {
+                display: flex;
+                justify-content: center;
+                margin-bottom: 0.5em;
+            }
             .row {
             .row {
                 padding-left: 1em;
                 padding-left: 1em;
             }
             }
             .occupant-details-nickname {
             .occupant-details-nickname {
                 font-size: var(--font-size-huge);
                 font-size: var(--font-size-huge);
             }
             }
+            .occupant-details-jid {
+                font-size: var(--font-size-small);
+            }
             .badge {
             .badge {
                 margin: 0.1em;
                 margin: 0.1em;
             }
             }

+ 64 - 48
src/plugins/muc-views/templates/muc-occupant.js

@@ -1,15 +1,15 @@
 import { html } from 'lit';
 import { html } from 'lit';
-import { until } from 'lit/directives/until.js';
-import { _converse, api, u } from "@converse/headless";
+import { _converse, u } from '@converse/headless';
 import { __ } from 'i18n';
 import { __ } from 'i18n';
 
 
 /**
 /**
  * @param {import('../occupant').default} el
  * @param {import('../occupant').default} el
  */
  */
 export default (el) => {
 export default (el) => {
-    const i18n_participants = __('Participants');
-    const i18n_add_to_contacts = __('Add to Contacts');
+    const i18n_close = __('Hide');
     const i18n_no_occupant = __('No participant data found');
     const i18n_no_occupant = __('No participant data found');
+    const i18n_participants = __('Participants');
+    const i18n_show_details = __('Show details');
 
 
     const jid = el.model?.get('jid');
     const jid = el.model?.get('jid');
     const nick = el.model?.get('nick');
     const nick = el.model?.get('nick');
@@ -17,51 +17,67 @@ export default (el) => {
     const affiliation = u.firstCharToUpperCase(el.model?.get('affiliation'));
     const affiliation = u.firstCharToUpperCase(el.model?.get('affiliation'));
     const hats = el.model?.get('hats')?.length ? el.model.get('hats').map(({ title }) => title) : [];
     const hats = el.model?.get('hats')?.length ? el.model.get('hats').map(({ title }) => title) : [];
 
 
-    const can_see_real_jids = el.muc.features.get('nonanonymous') || el.muc.getOwnRole() === 'moderator';
-    const bare_jid = _converse.session.get('bare_jid');
-    const not_me =  jid != bare_jid;
-
-    const add_to_contacts = api.settings.get('singleton')
-        ? '' // in singleton mode, there is no roster, so adding to contact makes no sense.
-        : api.contacts.get(jid)
-            .then(contact => !contact && not_me && can_see_real_jids)
-            .then(add => add ? html`<li><button class="btn btn-primary" type="button" @click=${() => el.addToContacts()}>${i18n_add_to_contacts}</button></li>` : '');
-
     return html`<div class="sidebar-heading">
     return html`<div class="sidebar-heading">
-            <button
-                type="button"
-                class="btn btn--transparent back-button"
-                @click=${() => el.muc.save({ 'sidebar_view': 'occupants' })}>
-                <converse-icon size="1em" class="fa fa-arrow-left"></converse-icon>
-            </button>
-            ${i18n_participants}</div>
+            <span
+                ><button
+                    type="button"
+                    class="btn btn--transparent back-button"
+                    @click=${() => el.muc.save({ 'sidebar_view': 'occupants' })}
+                >
+                    <converse-icon size="1em" class="fa fa-arrow-left"></converse-icon>
+                </button>
+                ${i18n_participants}
+            </span>
+            <converse-dropdown
+                .items=${[
+                    html`<a
+                        class="dropdown-item show-occupant-modal"
+                        role="button"
+                        title="${i18n_show_details}"
+                        @click=${() => el.showOccupantModal()}
+                    >
+                        <converse-icon class="fa fa-id-card" size="1em"></converse-icon>
+                        ${i18n_show_details}
+                    </a>`,
+                    html`<a href="#" class="dropdown-item" role="button" @click=${() => el.closeSidebar()}>
+                        <converse-icon size="1em" class="fa fa-times"></converse-icon>
+                        ${i18n_close}
+                    </a>`,
+                ]}
+            ></converse-dropdown>
+        </div>
 
 
-        ${el.model ? html`
-            <div class="row">
-                <div class="col">
-                    <converse-avatar
-                        .model=${el.model}
-                        class="avatar modal-avatar justify-content-center"
-                        name="${el.model.getDisplayName()}"
-                        nonce=${el.getVcard()?.get('vcard_updated')}
-                        height="120" width="120"></converse-avatar>
-                </div>
+        ${el.model
+            ? html` <div class="row">
+                  <div class="col">
+                      <converse-avatar
+                          .model=${el.model}
+                          class="avatar modal-avatar justify-content-center"
+                          name="${el.model.getDisplayName()}"
+                          nonce=${el.getVcard()?.get('vcard_updated')}
+                          height="120"
+                          width="120"
+                      ></converse-avatar>
+                  </div>
+              </div>`
+            : ''}
+        <div class="row">
+            <div class="col">
+                <ul class="occupant-details">
+                    ${el.model
+                        ? html` ${nick ? html`<li class="occupant-details-nickname">${nick}</li>` : ''}
+                              <li class="occupant-details-jid">
+                                  ${jid ? html`<a @click="${() => el.openChat(jid)}">${jid}</a>` : ''}
+                              </li>
+                              <li>
+                                  <span class="badge text-bg-primary">${affiliation}</span>
+                                  <span class="badge text-bg-secondary">${role}</span>
+                                  ${hats.length
+                                      ? html`${hats.map((h) => html`<span class="badge text-bg-info">${h}</span>`)}`
+                                      : ''}
+                              </li>`
+                        : html`<li>${i18n_no_occupant}</li>`}
+                </ul>
             </div>
             </div>
-            <div class="row">
-                <div class="col-auto">
-                    <ul class="occupant-details">
-                        ${ nick ? html`<li class="occupant-details-nickname">${nick}</li>` : '' }
-                        <li>
-                            ${ jid ? html`<div class="row"><strong class="g-0">${__('XMPP Address')}:</strong></div><div class="row">${jid}</div>` : '' }
-                        <li>
-                        <li>
-                            <span class="badge text-bg-primary">${affiliation}</span>
-                            <span class="badge text-bg-secondary">${role}</span>
-                            ${ hats.length ? html`${hats.map((h) => html`<span class="badge text-bg-info">${h}</span>`)}` : '' }
-                        </li>
-                        ${ until(add_to_contacts, '') }
-                    </ul>
-                </div>
-            </div>` : html`<p>${i18n_no_occupant}</p>`
-        }`;
+        </div>`;
 };
 };

+ 3 - 3
src/plugins/roomslist/templates/roomslist.js

@@ -158,20 +158,20 @@ export default (el) => {
 
 
     const btns = [
     const btns = [
         html`<a class="dropdown-item show-bookmark-list-modal" role="button"
         html`<a class="dropdown-item show-bookmark-list-modal" role="button"
-                @click=${(ev) => api.modal.show('converse-bookmark-list-modal', { 'model': el.model }, ev)}
+                @click="${(ev) => api.modal.show('converse-bookmark-list-modal', { 'model': el.model }, ev)}"
                 data-toggle="modal">
                 data-toggle="modal">
                     <converse-icon class="fa fa-bookmark" size="1em"></converse-icon>
                     <converse-icon class="fa fa-bookmark" size="1em"></converse-icon>
                     ${i18n_show_bookmarks}
                     ${i18n_show_bookmarks}
         </a>`,
         </a>`,
         html`<a class="dropdown-item show-list-muc-modal" role="button"
         html`<a class="dropdown-item show-list-muc-modal" role="button"
-                @click=${(ev) => api.modal.show('converse-muc-list-modal', { 'model': el.model }, ev)}
+                @click="${(ev) => api.modal.show('converse-muc-list-modal', { 'model': el.model }, ev)}"
                 data-toggle="modal"
                 data-toggle="modal"
                 data-target="#muc-list-modal">
                 data-target="#muc-list-modal">
                     <converse-icon class="fa fa-list-ul" size="1em"></converse-icon>
                     <converse-icon class="fa fa-list-ul" size="1em"></converse-icon>
                     ${i18n_title_list_rooms}
                     ${i18n_title_list_rooms}
         </a>`,
         </a>`,
         html`<a class="dropdown-item show-add-muc-modal" role="button"
         html`<a class="dropdown-item show-add-muc-modal" role="button"
-                @click=${(ev) => api.modal.show('converse-add-muc-modal', { 'model': el.model }, ev)}
+                @click="${(ev) => api.modal.show('converse-add-muc-modal', { 'model': el.model }, ev)}"
                 data-toggle="modal"
                 data-toggle="modal"
                 data-target="#add-chatrooms-modal">
                 data-target="#add-chatrooms-modal">
                     <converse-icon class="fa fa-plus" size="1em"></converse-icon>
                     <converse-icon class="fa fa-plus" size="1em"></converse-icon>

+ 3 - 3
src/plugins/rosterview/tests/roster.js

@@ -868,7 +868,7 @@ describe("The Contacts Roster", function () {
             await mock.waitForRoster(_converse, 'current', 1);
             await mock.waitForRoster(_converse, 'current', 1);
             await mock.openControlBox(_converse);
             await mock.openControlBox(_converse);
             const icon_el = document.querySelector('converse-roster-contact converse-icon');
             const icon_el = document.querySelector('converse-roster-contact converse-icon');
-            expect(icon_el.getAttribute('color')).toBe('var(--secondary-color)');
+            expect(icon_el.getAttribute('color')).toBe('var(--comment)');
 
 
             let pres = $pres({from: 'mercutio@montague.lit/resource'});
             let pres = $pres({from: 'mercutio@montague.lit/resource'});
             _converse.api.connection.get()._dataRecv(mock.createRequest(pres));
             _converse.api.connection.get()._dataRecv(mock.createRequest(pres));
@@ -880,7 +880,7 @@ describe("The Contacts Roster", function () {
 
 
             pres = $pres({from: 'mercutio@montague.lit/resource'}).c('show', 'xa');
             pres = $pres({from: 'mercutio@montague.lit/resource'}).c('show', 'xa');
             _converse.api.connection.get()._dataRecv(mock.createRequest(pres));
             _converse.api.connection.get()._dataRecv(mock.createRequest(pres));
-            await u.waitUntil(() => icon_el.getAttribute('color') === 'var(--secondary-color)');
+            await u.waitUntil(() => icon_el.getAttribute('color') === 'var(--comment)');
 
 
             pres = $pres({from: 'mercutio@montague.lit/resource'}).c('show', 'dnd');
             pres = $pres({from: 'mercutio@montague.lit/resource'}).c('show', 'dnd');
             _converse.api.connection.get()._dataRecv(mock.createRequest(pres));
             _converse.api.connection.get()._dataRecv(mock.createRequest(pres));
@@ -888,7 +888,7 @@ describe("The Contacts Roster", function () {
 
 
             pres = $pres({from: 'mercutio@montague.lit/resource', type: 'unavailable'});
             pres = $pres({from: 'mercutio@montague.lit/resource', type: 'unavailable'});
             _converse.api.connection.get()._dataRecv(mock.createRequest(pres));
             _converse.api.connection.get()._dataRecv(mock.createRequest(pres));
-            await u.waitUntil(() => icon_el.getAttribute('color') === 'var(--secondary-color)');
+            await u.waitUntil(() => icon_el.getAttribute('color') === 'var(--comment)');
         }));
         }));
 
 
         it("can be added to the roster and they will be sorted alphabetically",
         it("can be added to the roster and they will be sorted alphabetically",

+ 11 - 1
src/types/plugins/muc-views/occupant.d.ts

@@ -13,9 +13,19 @@ export default class MUCOccupant extends CustomElement {
     muc: any;
     muc: any;
     model: any;
     model: any;
     render(): import("lit").TemplateResult<1> | "";
     render(): import("lit").TemplateResult<1> | "";
+    /**
+     * @param {string} jid
+     */
+    openChat(jid: string): void;
+    closeSidebar(): void;
+    /** @param {MouseEvent} [ev] */
+    showOccupantModal(ev?: MouseEvent): void;
     getVcard(): any;
     getVcard(): any;
     addToContacts(): void;
     addToContacts(): void;
-    toggleForm(ev: any): void;
+    /**
+     * @param {MouseEvent} ev
+     */
+    toggleForm(ev: MouseEvent): void;
     show_role_form: any;
     show_role_form: any;
     show_affiliation_form: any;
     show_affiliation_form: any;
 }
 }