muc-views: Remove features section...

and replace with button to open invite modal
This commit is contained in:
JC Brand 2020-01-28 19:25:21 +01:00
parent 9fb2056753
commit 30d08d2bfe
5 changed files with 94 additions and 116 deletions

View File

@ -181,9 +181,10 @@
margin-bottom: 0.5em;
display: flex;
flex-direction: row;
.fa-user-plus {
margin-top: 0.2em;
}
.fa-user-plus {
margin-right: 0.5em;
}
.occupants-heading {

View File

@ -541,6 +541,22 @@ body.converse-fullscreen {
}
}
.btn-circle {
width: 32px;
height: 32px;
text-align: center;
padding: 0.5em 0;
font-size: var(--font-size-small);
line-height: 1.428571429;
border-radius: 50%;
}
.btn {
&.fa {
color: white !important;
}
}
.badge-groupchat {
background-color: var(--chatroom-badge-color);
border-color: transparent;

View File

@ -1944,16 +1944,16 @@
expect(view.model.getOwnAffiliation()).toBe('owner');
expect(view.model.features.get('open')).toBe(false);
expect(view.el.querySelector('.occupants-header .fa-user-plus')).not.toBe(null);
expect(view.el.querySelector('.open-invite-modal')).not.toBe(null);
// Members can't invite if the room isn't open
view.model.getOwnOccupant().set('affiliation', 'member');
await u.waitUntil(() => view.el.querySelector('.occupants-header .fa-user-plus') === null);
await u.waitUntil(() => view.el.querySelector('.open-invite-modal') === null);
view.model.features.set('open', 'true');
await u.waitUntil(() => view.el.querySelector('.occupants-header .fa-user-plus'));
await u.waitUntil(() => view.el.querySelector('.open-invite-modal'));
view.el.querySelector('.occupants-header .fa-user-plus').click();
view.el.querySelector('.open-invite-modal').click();
const modal = view.sidebar_view.muc_invite_modal;
await u.waitUntil(() => u.isVisible(modal.el), 1000)
@ -2506,26 +2506,38 @@
];
await test_utils.openAndEnterChatRoom(_converse, 'room@conference.example.org', 'romeo', features);
const jid = 'room@conference.example.org';
const chatroomview = _converse.chatboxviews.get(jid);
let features_list = chatroomview.el.querySelector('.features-list');
let features_shown = features_list.textContent.split('\n').map(s => s.trim()).filter(s => s);
expect(_.difference(["Password protected", "Open", "Temporary", "Not anonymous", "Not moderated"], features_shown).length).toBe(0);
expect(chatroomview.model.features.get('hidden')).toBe(false);
expect(chatroomview.model.features.get('mam_enabled')).toBe(false);
expect(chatroomview.model.features.get('membersonly')).toBe(false);
expect(chatroomview.model.features.get('moderated')).toBe(false);
expect(chatroomview.model.features.get('nonanonymous')).toBe(true);
expect(chatroomview.model.features.get('open')).toBe(true);
expect(chatroomview.model.features.get('passwordprotected')).toBe(true);
expect(chatroomview.model.features.get('persistent')).toBe(false);
expect(chatroomview.model.features.get('publicroom')).toBe(true);
expect(chatroomview.model.features.get('semianonymous')).toBe(false);
expect(chatroomview.model.features.get('temporary')).toBe(true);
expect(chatroomview.model.features.get('unmoderated')).toBe(true);
expect(chatroomview.model.features.get('unsecured')).toBe(false);
expect(chatroomview.el.querySelector('.chatbox-title__text').textContent.trim()).toBe('Room');
const view = _converse.chatboxviews.get(jid);
chatroomview.el.querySelector('.configure-chatroom-button').click();
const info_el = view.el.querySelector(".show-room-details-modal");
info_el.click();
const modal = view.model.room_details_modal;
await u.waitUntil(() => u.isVisible(modal.el), 1000);
let features_list = modal.el.querySelector('.features-list');
let features_shown = features_list.textContent.split('\n').map(s => s.trim()).filter(s => s);
expect(features_shown.join(' ')).toBe(
'Password protected - This groupchat requires a password before entry '+
'Open - Anyone can join this groupchat '+
'Temporary - This groupchat will disappear once the last person leaves '+
'Not anonymous - All other groupchat participants can see your XMPP address '+
'Not moderated - Participants entering this groupchat can write right away');
expect(view.model.features.get('hidden')).toBe(false);
expect(view.model.features.get('mam_enabled')).toBe(false);
expect(view.model.features.get('membersonly')).toBe(false);
expect(view.model.features.get('moderated')).toBe(false);
expect(view.model.features.get('nonanonymous')).toBe(true);
expect(view.model.features.get('open')).toBe(true);
expect(view.model.features.get('passwordprotected')).toBe(true);
expect(view.model.features.get('persistent')).toBe(false);
expect(view.model.features.get('publicroom')).toBe(true);
expect(view.model.features.get('semianonymous')).toBe(false);
expect(view.model.features.get('temporary')).toBe(true);
expect(view.model.features.get('unmoderated')).toBe(true);
expect(view.model.features.get('unsecured')).toBe(false);
expect(view.el.querySelector('.chatbox-title__text').textContent.trim()).toBe('Room');
view.el.querySelector('.configure-chatroom-button').click();
const IQs = _converse.connection.IQ_stanzas;
let iq = await u.waitUntil(() => _.filter(
@ -2602,9 +2614,9 @@
_converse.connection._dataRecv(test_utils.createRequest(response_el));
const el = await u.waitUntil(() => document.querySelector('.chatroom-form legend'));
expect(el.textContent.trim()).toBe("Configuration for room@conference.example.org");
sizzle('[name="muc#roomconfig_membersonly"]', chatroomview.el).pop().click();
sizzle('[name="muc#roomconfig_roomname"]', chatroomview.el).pop().value = "New room name"
chatroomview.el.querySelector('.chatroom-form input[type="submit"]').click();
sizzle('[name="muc#roomconfig_membersonly"]', view.el).pop().click();
sizzle('[name="muc#roomconfig_roomname"]', view.el).pop().value = "New room name"
view.el.querySelector('.chatroom-form input[type="submit"]').click();
iq = await u.waitUntil(() => _.filter(IQs, iq => u.matchesSelector(iq, `iq[to="${jid}"][type="set"]`)).pop());
const result = $iq({
@ -2656,24 +2668,30 @@
_converse.connection._dataRecv(test_utils.createRequest(features_stanza));
await u.waitUntil(() => new Promise(success => chatroomview.model.features.on('change', success)));
features_list = chatroomview.el.querySelector('.features-list');
await u.waitUntil(() => new Promise(success => view.model.features.on('change', success)));
features_list = modal.el.querySelector('.features-list');
features_shown = features_list.textContent.split('\n').map(s => s.trim()).filter(s => s);
expect(_.difference(["Password protected", "Hidden", "Members only", "Temporary", "Not anonymous", "Not moderated"], features_shown).length).toBe(0);
expect(chatroomview.model.features.get('hidden')).toBe(true);
expect(chatroomview.model.features.get('mam_enabled')).toBe(false);
expect(chatroomview.model.features.get('membersonly')).toBe(true);
expect(chatroomview.model.features.get('moderated')).toBe(false);
expect(chatroomview.model.features.get('nonanonymous')).toBe(true);
expect(chatroomview.model.features.get('open')).toBe(false);
expect(chatroomview.model.features.get('passwordprotected')).toBe(true);
expect(chatroomview.model.features.get('persistent')).toBe(false);
expect(chatroomview.model.features.get('publicroom')).toBe(false);
expect(chatroomview.model.features.get('semianonymous')).toBe(false);
expect(chatroomview.model.features.get('temporary')).toBe(true);
expect(chatroomview.model.features.get('unmoderated')).toBe(true);
expect(chatroomview.model.features.get('unsecured')).toBe(false);
expect(chatroomview.el.querySelector('.chatbox-title__text').textContent.trim()).toBe('New room name');
expect(features_shown.join(' ')).toBe(
'Password protected - This groupchat requires a password before entry '+
'Hidden - This groupchat is not publicly searchable '+
'Members only - This groupchat is restricted to members only '+
'Temporary - This groupchat will disappear once the last person leaves '+
'Not anonymous - All other groupchat participants can see your XMPP address '+
'Not moderated - Participants entering this groupchat can write right away');
expect(view.model.features.get('hidden')).toBe(true);
expect(view.model.features.get('mam_enabled')).toBe(false);
expect(view.model.features.get('membersonly')).toBe(true);
expect(view.model.features.get('moderated')).toBe(false);
expect(view.model.features.get('nonanonymous')).toBe(true);
expect(view.model.features.get('open')).toBe(false);
expect(view.model.features.get('passwordprotected')).toBe(true);
expect(view.model.features.get('persistent')).toBe(false);
expect(view.model.features.get('publicroom')).toBe(false);
expect(view.model.features.get('semianonymous')).toBe(false);
expect(view.model.features.get('temporary')).toBe(true);
expect(view.model.features.get('unmoderated')).toBe(true);
expect(view.model.features.get('unsecured')).toBe(false);
expect(view.el.querySelector('.chatbox-title__text').textContent.trim()).toBe('New room name');
done();
}));

View File

@ -615,6 +615,7 @@ converse.plugins.add('converse-muc-views', {
initialize () {
_converse.BootstrapModal.prototype.initialize.apply(this, arguments);
this.listenTo(this.model, 'change', this.render);
this.listenTo(this.model.features, 'change', this.render);
this.listenTo(this.model.occupants, 'add', this.render);
this.listenTo(this.model.occupants, 'change', this.render);
},

View File

@ -1,9 +1,8 @@
import { html } from "lit-html";
import { __ } from '@converse/headless/i18n';
import { pick } from "lodash";
import converse from "@converse/headless/converse-core";
import tpl_occupant from "./occupant.js";
const PRETTY_CHAT_STATUS = {
'offline': 'Offline',
'unavailable': 'Unavailable',
@ -16,77 +15,21 @@ const PRETTY_CHAT_STATUS = {
const occupant_hint = (occupant) => __('Click to mention %1$s in your message.', occupant.get('nick'))
const i18n_archived = __('Message archiving');
const i18n_archived_hint = __('Messages are archived on the server');
const i18n_features = __('Features');
const i18n_hidden = __('Hidden');
const i18n_invite_hint = __('Invite people to join this groupchat');
const i18n_members_only = __('Members only');
const i18n_members_only_hint = __('this groupchat is restricted to members only');
const i18n_moderated = __('Moderated');
const i18n_moderated_hint = __('Participants entering this groupchat need to request permission to write');
const i18n_no_password = __('No password');
const i18n_no_password_hint = __('This groupchat does not require a password upon entry');
const i18n_non_anon_hint = __('All other groupchat participants can see your XMPP address');
const i18n_not_anon = __('Not anonymous');
const i18n_not_moderated = __('Not moderated');
const i18n_not_searchable_hint = __('This groupchat is not publicly searchable');
const i18n_open = __('Open');
const i18n_open_hint = __('Anyone can join this groupchat');
const i18n_invite_hint = __('Invite someone');
const i18n_participants = __('Participants');
const i18n_password = __('Password protected')
const i18n_password_hint = __('This groupchat requires a password before entry');
const i18n_persistent = __('Persistent');
const i18n_persistent_hint = __('This groupchat persists even if it\'s unoccupied');
const i18n_public = __('Public');
const i18n_searchable_hint = __('This groupchat is publicly searchable');
const i18n_semi_anon = __('Semi-anonymous');
const i18n_semi_anon_hint = __('Only moderators can see your XMPP address');
const i18n_temporary = __('Temporary');
const i18n_temporary_hint = __('This groupchat will disappear once the last person leaves');
const i18n_unmoderated_hint = __('Participants entering this groupchat can write right away');
function renderFeatures (o) {
const picks = pick(o.features.attributes, converse.ROOM_FEATURES);
const iteratee = (a, v) => a || v;
if (Object.values(picks).reduce(iteratee)) {
return tpl_features(o.features.toJSON());
} else {
return '';
}
}
const tpl_features = (o) => html`
<div class="chatroom-features">
<p class="occupants-heading">${i18n_features}</p>
<ul class="features-list">
${ (o.passwordprotected) ? html`<li class="feature" title="${ i18n_password_hint }"><span class="fa fa-lock"></span>${ i18n_password }</li>` : '' }
${ (o.unsecured) ? html`<li class="feature" title="${ i18n_no_password_hint }"><span class="fa fa-unlock"></span>${ i18n_no_password }</li>` : '' }
${ (o.hidden) ? html`<li class="feature" title="${ i18n_not_searchable_hint }"><span class="fa fa-eye-slash"></span>${ i18n_hidden }</li>` : '' }
${ (o.public_room) ? html`<li class="feature" title="${ i18n_searchable_hint }"><span class="fa fa-eye"></span>${ i18n_public }</li>` : '' }
${ (o.membersonly) ? html`<li class="feature" title="${ i18n_members_only_hint }"><span class="fa fa-address-book"></span>${ i18n_members_only }</li>` : '' }
${ (o.open) ? html`<li class="feature" title="${ i18n_open_hint }"><span class="fa fa-globe"></span>${ i18n_open }</li>` : '' }
${ (o.persistent) ? html`<li class="feature" title="${ i18n_persistent_hint }"><span class="fa fa-save"></span>${ i18n_persistent }</li>` : '' }
${ (o.temporary) ? html`<li class="feature" title="${ i18n_temporary_hint }"><span class="fa fa-snowflake"></span>${ i18n_temporary }</li>` : '' }
${ (o.nonanonymous) ? html`<li class="feature" title="${ i18n_non_anon_hint }"><span class="fa fa-id-card"></span>${ i18n_not_anon }</li>` : '' }
${ (o.semianonymous) ? html`<li class="feature" title="${ i18n_semi_anon_hint }"><span class="fa fa-user-secret"></span>${ i18n_semi_anon }</li>` : '' }
${ (o.moderated) ? html`<li class="feature" title="${ i18n_moderated_hint }"><span class="fa fa-gavel"></span>${ i18n_moderated }</li>` : '' }
${ (o.unmoderated) ? html`<li class="feature" title="${ i18n_unmoderated_hint }"><span class="fa fa-info-circle"></span>${ i18n_not_moderated }</li>` : '' }
${ (o.mam_enabled) ? html`<li class="feature" title="${ i18n_archived_hint }"><span class="fa fa-database"></span>${ i18n_archived }</li>` : '' }
</ul>
</div>
`;
const invite_button = (o) => {
const invite_widget = (o) => {
if (o.invitesAllowed()) {
return html`
<a class="fa fa-user-plus"
<a class="open-invite-modal"
title="${i18n_invite_hint}"
@click=${o.showInviteModal}
data-toggle="modal"
data-target="#muc-invite-modal"></a>`;
data-target="#muc-invite-modal"
@click=${o.showInviteModal}>
<i class="btn btn-primary btn-circle fa fa-user-plus"></i>
${i18n_invite_hint}
</a>`;
} else {
return '';
}
@ -98,7 +41,6 @@ export default (o) => html`
<i class="hide-occupants fa fa-times"></i>
<div class="occupants-header--title">
<span class="occupants-heading">${i18n_participants}</span>
${ invite_button(o) }
</div>
</div>
<div class="dragresize dragresize-occupants-left"></div>
@ -113,5 +55,5 @@ export default (o) => html`
);
}) }
</ul>
${ renderFeatures(o) }
${ invite_widget(o) }
`;