Explorar o código

More work on showing a detailed MUC occupant view in the sidebar

JC Brand hai 8 meses
pai
achega
13cd125d8c

+ 10 - 28
src/headless/utils/index.js

@@ -3,20 +3,19 @@
  * @license Mozilla Public License (MPLv2)
  * @description This is the core utilities module.
  */
-import { toStanza } from 'strophe.js';
-import { getOpenPromise } from '@converse/openpromise';
 import { Model } from '@converse/skeletor';
 import log, { LEVELS } from '../log.js';
-import { waitUntil } from './promise.js';
+import * as arraybuffer from './arraybuffer.js';
 import * as color from './color.js';
-import * as stanza from './stanza.js';
-import * as session from './session.js';
-import * as object from './object.js';
-import * as storage from './storage.js';
-import * as jid from './jid';
 import * as form from './form.js';
 import * as html from './html.js';
-import * as arraybuffer from './arraybuffer.js';
+import * as jid from './jid';
+import * as object from './object.js';
+import * as promise from './promise.js';
+import * as session from './session.js';
+import * as stanza from './stanza.js';
+import * as storage from './storage.js';
+import * as text from './text.js';
 import * as url from './url.js';
 
 /**
@@ -72,21 +71,6 @@ export function prefixMentions (message) {
     return text;
 }
 
-function getLongestSubstring (string, candidates) {
-    function reducer (accumulator, current_value) {
-        if (string.startsWith(current_value)) {
-            if (current_value.length > accumulator.length) {
-                return current_value;
-            } else {
-                return accumulator;
-            }
-        } else {
-            return accumulator;
-        }
-    }
-    return candidates.reduce(reducer, '');
-}
-
 function shouldCreateMessage (attrs) {
     return attrs['retracted'] || // Retraction received *before* the message
         !isEmptyMessage(attrs);
@@ -170,12 +154,12 @@ export default Object.assign({
     ...html,
     ...jid,
     ...object,
+    ...promise,
     ...session,
     ...stanza,
     ...storage,
+    ...text,
     ...url,
-    getLongestSubstring,
-    getOpenPromise,
     getRandomInt,
     getUniqueId,
     isEmptyMessage,
@@ -184,7 +168,5 @@ export default Object.assign({
     prefixMentions,
     safeSave,
     shouldCreateMessage,
-    toStanza,
     triggerEvent,
-    waitUntil, // TODO: remove. Only the API should be used
 }, u);

+ 2 - 0
src/headless/utils/promise.js

@@ -1,6 +1,8 @@
 import log from '../log.js';
 import { getOpenPromise } from '@converse/openpromise';
 
+export { getOpenPromise };
+
 /**
  * Clears the specified timeout and interval.
  * @method u#clearTimers

+ 3 - 0
src/headless/utils/stanza.js

@@ -1,6 +1,9 @@
 import sizzle from "sizzle";
 import { Strophe } from 'strophe.js';
 import { isElement } from './html.js';
+import { toStanza } from 'strophe.js';
+
+export { toStanza };
 
 /**
  * @param {Element} stanza

+ 43 - 0
src/headless/utils/text.js

@@ -0,0 +1,43 @@
+/**
+ * @param {string} text
+ * @returns {string}
+ */
+export function firstCharToUpperCase(text) {
+    if (!text) {
+        return '';
+    }
+
+    if ('\uD83D\uDE00'.length === 1) {
+        return text.charAt(0).toLocaleUpperCase() + text.substring(1);
+    }
+
+    const firstChar = text.codePointAt(0);
+    const index = firstChar > 0xffff ? 2 : 1;
+
+    return String.fromCodePoint(firstChar).toLocaleUpperCase() + text.substring(index);
+}
+
+/**
+ * @param {string} string
+ * @param {string[]} candidates
+ * @returns {string}
+ */
+export function getLongestSubstring (string, candidates) {
+    /**
+     * @param {string} accumulator
+     * @param {string} current_value
+     * @returns {string}
+     */
+    function reducer (accumulator, current_value) {
+        if (string.startsWith(current_value)) {
+            if (current_value.length > accumulator.length) {
+                return current_value;
+            } else {
+                return accumulator;
+            }
+        } else {
+            return accumulator;
+        }
+    }
+    return candidates.reduce(reducer, '');
+}

+ 6 - 3
src/plugins/muc-views/occupant.js

@@ -23,16 +23,19 @@ export default class MUCOccupant extends CustomElement {
         }
     }
 
-    initialize() {
+    async initialize() {
         super.initialize()
+
         const { chatboxes } = _converse.state;
         this.muc = chatboxes.get(this.muc_jid);
-        this.muc.initialized.then(() => this.requestUpdate());
+        await this.muc.initialized;
+
         this.model = this.muc.occupants.get(this.occupant_id);
+        this.requestUpdate();
     }
 
     render () {
-        return tplMUCOccupant(this);
+        return this.muc ? tplMUCOccupant(this) : '';
     }
 
     getVcard () {

+ 0 - 40
src/plugins/muc-views/styles/index.scss

@@ -27,9 +27,6 @@ converse-muc-destroyed {
     }
 }
 
-
-/* ******************* Overlay  styles *************************** */
-
 .conversejs {
     converse-chats {
         &.converse-overlayed {
@@ -53,23 +50,6 @@ converse-muc-destroyed {
                         margin-bottom: 1em;
                     }
                     .chatroom-body {
-                        .occupants {
-                            .occupants-heading {
-                                padding: 0;
-                            }
-                            .occupant-list {
-                                border-bottom: none;
-                            }
-                            ul {
-                                .occupant {
-                                    .occupant-nick-badge {
-                                        .occupant-badges {
-                                            display: none;
-                                        }
-                                    }
-                                }
-                            }
-                        }
                         .chat-area {
                             min-width: var(--overlayed-chat-width);
                         }
@@ -93,18 +73,6 @@ converse-muc-destroyed {
                                 }
                             }
                         }
-                        .occupants {
-                            .occupants-heading {
-                                font-size: var(--font-size-large);
-                            }
-                            ul {
-                                &.occupant-list {
-                                    li {
-                                        font-size: var(--font-size-small);
-                                    }
-                                }
-                            }
-                        }
                     }
                 }
                 .room-invite {
@@ -122,9 +90,6 @@ converse-muc-destroyed {
                 margin: 0;
                 width: 100%;
                 .box-flyout {
-                    .occupants-heading {
-                        font-size: 120%;
-                    }
                     .chat-content {
                         .chat-message {
                             margin: 0.5em;
@@ -144,11 +109,6 @@ converse-muc-destroyed {
                             position: relative;
                         }
                     }
-                    .occupants {
-                        .occupant-list {
-                            padding-left: 0.3em;
-                        }
-                    }
                 }
             }
         }

+ 16 - 1
src/plugins/muc-views/styles/muc-occupant.scss

@@ -1,8 +1,23 @@
 .conversejs {
     converse-muc-occupant {
+        width: 100%;
+
         .back-button {
-            font-size: 10px;
+            font-size: 0.75em;
             padding: 0.5em;
         }
+
+        .occupant-details {
+            padding-left: 0.3em;
+            .row {
+                padding-left: 1em;
+            }
+            .occupant-details-nickname {
+                font-size: var(--font-size-huge);
+            }
+            .badge {
+                margin: 0.1em;
+            }
+        }
     }
 }

+ 45 - 5
src/plugins/muc-views/styles/muc-occupants.scss

@@ -16,11 +16,6 @@
                 flex-direction: row;
                 padding: 0.5em;
 
-                .occupants-heading {
-                    padding-left: 0;
-                    margin-right: 0.5em;
-                }
-
                 .hide-occupants {
                     align-self: flex-end;
                     cursor: pointer;
@@ -121,4 +116,49 @@
             }
         }
     }
+
+    converse-chats{
+        &.converse-overlayed {
+            converse-muc-occupants {
+                .occupants {
+                    .occupant-list {
+                        border-bottom: none;
+                    }
+                    ul {
+                        .occupant {
+                            .occupant-nick-badge {
+                                .occupant-badges {
+                                    display: none;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        &.converse-embedded,
+        &.converse-fullscreen {
+            converse-muc-occupants {
+                .occupants {
+                    ul {
+                        &.occupant-list {
+                            li {
+                                font-size: var(--font-size-small);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        &.converse-embedded {
+            converse-muc-occupants {
+                .occupants {
+                    .occupant-list {
+                        padding-left: 0.3em;
+                    }
+                }
+            }
+        }
+    }
 }

+ 25 - 0
src/plugins/muc-views/styles/muc-sidebar.scss

@@ -12,6 +12,31 @@
             font-family: var(--heading-font);
             color: var(--muc-color);
             padding-left: 0;
+            margin-right: 0.5em;
+        }
+    }
+
+    converse-chats {
+        &.converse-overlayed {
+            converse-muc-sidebar {
+                .sidebar-heading {
+                    padding: 0;
+                }
+            }
+        }
+        &.converse-fullscreen {
+            converse-muc-sidebar {
+                .sidebar-heading {
+                    font-size: var(--font-size-large);
+                }
+            }
+        }
+        &.converse-embedded {
+            converse-muc-sidebar {
+                .sidebar-heading {
+                    font-size: 120%;
+                }
+            }
         }
     }
 }

+ 13 - 47
src/plugins/muc-views/templates/muc-occupant.js

@@ -1,27 +1,22 @@
 import { html } from 'lit';
 import { until } from 'lit/directives/until.js';
-import { _converse, api } from "@converse/headless";
+import { _converse, api, u } from "@converse/headless";
 import { __ } from 'i18n';
 
 /**
  * @param {import('../occupant').default} el
  */
 export default (el) => {
-    const i18n_nickname = __('Nickname');
-    const i18n_affiliation = __('Affiliation');
     const i18n_participants = __('Participants');
     const i18n_add_to_contacts = __('Add to Contacts');
     const i18n_no_occupant = __('No participant data found');
 
     const jid = el.model?.get('jid');
     const nick = el.model?.get('nick');
-    const occupant_id = el.model?.get('occupant_id');
-    const role = el.model?.get('role');
-    const affiliation = el.model?.get('affiliation');
-    const hats = el.model?.get('hats')?.length ? el.model.get('hats') : null;
+    const role = u.firstCharToUpperCase(el.model?.get('role'));
+    const affiliation = u.firstCharToUpperCase(el.model?.get('affiliation'));
+    const hats = el.model?.get('hats')?.length ? el.model.get('hats').map(({ title }) => title) : [];
 
-    const allowed_commands = el.muc.getAllowedCommands();
-    const may_moderate = allowed_commands.includes('modtools');
     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;
@@ -45,55 +40,26 @@ export default (el) => {
 
         ${el.model ? html`
             <div class="row">
-                <div class="col-auto">
+                <div class="col">
                     <converse-avatar
                         .model=${el.model}
-                        class="avatar modal-avatar"
+                        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 class="col">
+            </div>
+            <div class="row">
+                <div class="col-auto">
                     <ul class="occupant-details">
-                        <li>
-                            ${ nick ? html`<div class="row"><strong class="g-0">${i18n_nickname}:</strong></div><div class="row">${nick}</div>` : '' }
-                        </li>
+                        ${ 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>
-                            <div class="row"><strong class="g-0">${i18n_affiliation}:</strong></div>
-                            <div class="row">${affiliation}&nbsp;
-                                ${ may_moderate ? html`
-                                    <a href="#"
-                                    data-form="affiliation-form"
-                                    class="toggle-form right"
-                                    color="var(--secondary-color)"
-                                    @click=${(ev) => el.toggleForm(ev)}><converse-icon class="fa fa-wrench" size="1em"></converse-icon>
-                                    </a>
-                                    ${ el.show_affiliation_form ? html`<converse-muc-affiliation-form jid=${jid} .muc=${el.muc} affiliation=${affiliation}></converse-muc-affiliation-form>` : '' }` : ''
-                                }
-                            </div>
-                        </li>
                         <li>
-                            <div class="row"><strong class="g-0">${__('Role')}:</strong></div>
-                            <div class="row">${role}&nbsp;
-                                ${ may_moderate && role ? html`
-                                    <a href="#"
-                                    data-form="row-form"
-                                    class="toggle-form right"
-                                    color="var(--secondary-color)"
-                                    @click=${(ev) => el.toggleForm(ev)}><converse-icon class="fa fa-wrench" size="1em"></converse-icon>
-                                    </a>
-                                    ${ el.show_role_form ? html`<converse-muc-role-form jid=${jid} .muc=${el.muc} role=${role}></converse-muc-role-form>` : '' }` : ''
-                                }
-                            </div>
-                        </li>
-                        <li>
-                            ${ hats ? html`<div class="row"><strong class="g-0">${__('Hats')}:</strong></div><div class="row">${hats}</div>` : '' }
-                        </li>
                         <li>
-                            ${ occupant_id ? html`<div class="row"><strong class="g-0">${__('Occupant Id')}:</strong></div><div class="row">${occupant_id}</div>` : '' }
+                            <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>

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

@@ -5,7 +5,7 @@ import { html } from 'lit';
  */
 export default (el) => {
     const model = el.model;
-    const sidebar_view = model.get('sidebar_view');
+    const sidebar_view = model.get('sidebar_view') || '';
     const occupant_id = sidebar_view.split('occupant:').pop();
     return html`
         <div class="dragresize-occupants-left">&nbsp;</div>

+ 1 - 1
src/plugins/muc-views/tests/muc-private-messages.js

@@ -2,7 +2,7 @@
 const { stx, u } = converse.env;
 
 describe('When receiving a MUC private message', function () {
-    fit(
+    it(
         "doesn't appear in the main MUC chatarea",
         mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
             const muc_jid = 'coven@chat.shakespeare.lit';

+ 1 - 1
src/shared/avatar/avatar.scss

@@ -7,7 +7,7 @@ converse-avatar {
     }
 
     &.modal-avatar {
-        display: block;
+        display: flex;
         margin-bottom: 1em;
     }