Move MUC invite widget into a modal
This commit is contained in:
parent
c6ac03e94e
commit
9fb2056753
4
package-lock.json
generated
4
package-lock.json
generated
|
@ -16094,8 +16094,8 @@
|
|||
"dev": true
|
||||
},
|
||||
"skeletor.js": {
|
||||
"version": "github:skeletorjs/skeletor#29a6d8f707076e865133b8f36f07c76ba4b4b582",
|
||||
"from": "github:skeletorjs/skeletor#29a6d8f707076e865133b8f36f07c76ba4b4b582",
|
||||
"version": "github:skeletorjs/skeletor#9a4487496bd2810b2f0847acbca136333cf9cfb0",
|
||||
"from": "github:skeletorjs/skeletor#9a4487496bd2810b2f0847acbca136333cf9cfb0",
|
||||
"requires": {
|
||||
"lodash": "^4.17.14"
|
||||
}
|
||||
|
|
|
@ -172,12 +172,25 @@
|
|||
.hide-occupants {
|
||||
align-self: flex-end;
|
||||
cursor: pointer;
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
}
|
||||
|
||||
.occupants-header--title {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
.fa-user-plus {
|
||||
margin-top: 0.2em;
|
||||
}
|
||||
}
|
||||
|
||||
.occupants-heading {
|
||||
font-family: var(--heading-font);
|
||||
margin-bottom: 0.5em;
|
||||
color: var(--chatroom-head-color);
|
||||
padding-left: 0;
|
||||
margin-right: 1em;
|
||||
}
|
||||
.chatroom-features {
|
||||
display: var(--occupants-features-display);
|
||||
|
|
38
spec/muc.js
38
spec/muc.js
|
@ -1940,36 +1940,54 @@
|
|||
'muc_anonymous'
|
||||
]
|
||||
await test_utils.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo', features);
|
||||
spyOn(_converse.api, "trigger").and.callThrough();
|
||||
spyOn(window, 'prompt').and.callFake(() => "Please join!");
|
||||
const view = _converse.chatboxviews.get('lounge@montague.lit');
|
||||
|
||||
expect(view.model.getOwnAffiliation()).toBe('owner');
|
||||
expect(view.model.features.get('open')).toBe(false);
|
||||
expect(view.el.querySelectorAll('input.invited-contact').length).toBe(1);
|
||||
|
||||
expect(view.el.querySelector('.occupants-header .fa-user-plus')).not.toBe(null);
|
||||
|
||||
// Members can't invite if the room isn't open
|
||||
view.model.getOwnOccupant().set('affiliation', 'member');
|
||||
await u.waitUntil(() => view.el.querySelectorAll('input.invited-contact').length === 0);
|
||||
await u.waitUntil(() => view.el.querySelector('.occupants-header .fa-user-plus') === null);
|
||||
|
||||
view.model.features.set('open', 'true');
|
||||
await u.waitUntil(() => view.el.querySelector('.occupants-header .fa-user-plus'));
|
||||
|
||||
view.el.querySelector('.occupants-header .fa-user-plus').click();
|
||||
const modal = view.sidebar_view.muc_invite_modal;
|
||||
await u.waitUntil(() => u.isVisible(modal.el), 1000)
|
||||
|
||||
expect(modal.el.querySelectorAll('#invitee_jids').length).toBe(1);
|
||||
expect(modal.el.querySelectorAll('textarea').length).toBe(1);
|
||||
|
||||
spyOn(view.model, 'directInvite').and.callThrough();
|
||||
await u.waitUntil(() => view.el.querySelectorAll('input.invited-contact').length);
|
||||
const input = view.el.querySelector('input.invited-contact');
|
||||
expect(input.getAttribute('placeholder')).toBe('Invite');
|
||||
|
||||
const input = modal.el.querySelector('#invitee_jids');
|
||||
input.value = "Balt";
|
||||
modal.el.querySelector('button[type="submit"]').click();
|
||||
|
||||
await u.waitUntil(() => modal.el.querySelector('.error'));
|
||||
|
||||
const error = modal.el.querySelector('.error');
|
||||
expect(error.textContent).toBe('Please enter a valid XMPP address');
|
||||
|
||||
let evt = new Event('input');
|
||||
input.dispatchEvent(evt);
|
||||
|
||||
let sent_stanza;
|
||||
spyOn(_converse.connection, 'send').and.callFake(stanza => (sent_stanza = stanza));
|
||||
const hint = await u.waitUntil(() => view.el.querySelector('.suggestion-box__results li'));
|
||||
const hint = await u.waitUntil(() => modal.el.querySelector('.suggestion-box__results li'));
|
||||
expect(input.value).toBe('Balt');
|
||||
expect(hint.textContent.trim()).toBe('Balthasar');
|
||||
|
||||
evt = new Event('mousedown', {'bubbles': true});
|
||||
evt.button = 0;
|
||||
hint.dispatchEvent(evt);
|
||||
expect(window.prompt).toHaveBeenCalled();
|
||||
|
||||
const textarea = modal.el.querySelector('textarea');
|
||||
textarea.value = "Please join!";
|
||||
modal.el.querySelector('button[type="submit"]').click();
|
||||
|
||||
expect(view.model.directInvite).toHaveBeenCalled();
|
||||
expect(sent_stanza.toLocaleString()).toBe(
|
||||
`<message from="romeo@montague.lit/orchard" `+
|
||||
|
|
|
@ -23,7 +23,7 @@ import tpl_chatroom_details_modal from "templates/chatroom_details_modal.js";
|
|||
import tpl_chatroom_disconnect from "templates/chatroom_disconnect.html";
|
||||
import tpl_muc_config_form from "templates/muc_config_form.js";
|
||||
import tpl_chatroom_head from "templates/chatroom_head.html";
|
||||
import tpl_chatroom_invite from "templates/chatroom_invite.html";
|
||||
import tpl_muc_invite_modal from "templates/muc_invite_modal.js";
|
||||
import tpl_chatroom_nickname_form from "templates/chatroom_nickname_form.html";
|
||||
import tpl_muc_password_form from "templates/muc_password_form.js";
|
||||
import tpl_muc_sidebar from "templates/muc_sidebar.js";
|
||||
|
@ -701,7 +701,7 @@ converse.plugins.add('converse-muc-views', {
|
|||
this.onMouseUp = this.onMouseUp.bind(this);
|
||||
|
||||
this.render();
|
||||
this.createOccupantsView();
|
||||
this.createSidebarView();
|
||||
await this.updateAfterMessagesFetched();
|
||||
this.onConnectionStatusChanged();
|
||||
/**
|
||||
|
@ -770,15 +770,15 @@ converse.plugins.add('converse-muc-views', {
|
|||
return this;
|
||||
},
|
||||
|
||||
createOccupantsView () {
|
||||
createSidebarView () {
|
||||
this.model.occupants.chatroomview = this;
|
||||
this.occupants_view = new _converse.ChatRoomOccupantsView({'model': this.model.occupants});
|
||||
this.sidebar_view = new _converse.MUCSidebar({'model': this.model.occupants});
|
||||
const container_el = this.el.querySelector('.chatroom-body');
|
||||
const occupants_width = this.model.get('occupants_width');
|
||||
if (this.occupants_view && occupants_width !== undefined) {
|
||||
this.occupants_view.el.style.flex = "0 0 " + occupants_width + "px";
|
||||
if (this.sidebar_view && occupants_width !== undefined) {
|
||||
this.sidebar_view.el.style.flex = "0 0 " + occupants_width + "px";
|
||||
}
|
||||
container_el.insertAdjacentElement('beforeend', this.occupants_view.el);
|
||||
container_el.insertAdjacentElement('beforeend', this.sidebar_view.el);
|
||||
},
|
||||
|
||||
onStartResizeOccupants (ev) {
|
||||
|
@ -786,7 +786,7 @@ converse.plugins.add('converse-muc-views', {
|
|||
this.el.addEventListener('mousemove', this.onMouseMove);
|
||||
this.el.addEventListener('mouseup', this.onMouseUp);
|
||||
|
||||
const style = window.getComputedStyle(this.occupants_view.el);
|
||||
const style = window.getComputedStyle(this.sidebar_view.el);
|
||||
this.width = parseInt(style.width.replace(/px$/, ''), 10);
|
||||
this.prev_pageX = ev.pageX;
|
||||
},
|
||||
|
@ -795,7 +795,7 @@ converse.plugins.add('converse-muc-views', {
|
|||
if (this.resizing) {
|
||||
ev.preventDefault();
|
||||
const delta = this.prev_pageX - ev.pageX;
|
||||
this.resizeOccupantsView(delta, ev.pageX);
|
||||
this.resizeSidebarView(delta, ev.pageX);
|
||||
this.prev_pageX = ev.pageX;
|
||||
}
|
||||
},
|
||||
|
@ -806,26 +806,26 @@ converse.plugins.add('converse-muc-views', {
|
|||
this.resizing = false;
|
||||
this.el.removeEventListener('mousemove', this.onMouseMove);
|
||||
this.el.removeEventListener('mouseup', this.onMouseUp);
|
||||
const element_position = this.occupants_view.el.getBoundingClientRect();
|
||||
const occupants_width = this.calculateOccupantsWidth(element_position, 0);
|
||||
const element_position = this.sidebar_view.el.getBoundingClientRect();
|
||||
const occupants_width = this.calculateSidebarWidth(element_position, 0);
|
||||
const attrs = {occupants_width};
|
||||
_converse.connection.connected ? this.model.save(attrs) : this.model.set(attrs);
|
||||
}
|
||||
},
|
||||
|
||||
resizeOccupantsView (delta, current_mouse_position) {
|
||||
const element_position = this.occupants_view.el.getBoundingClientRect();
|
||||
resizeSidebarView (delta, current_mouse_position) {
|
||||
const element_position = this.sidebar_view.el.getBoundingClientRect();
|
||||
if (this.is_minimum) {
|
||||
this.is_minimum = element_position.left < current_mouse_position;
|
||||
} else if (this.is_maximum) {
|
||||
this.is_maximum = element_position.left > current_mouse_position;
|
||||
} else {
|
||||
const occupants_width = this.calculateOccupantsWidth(element_position, delta);
|
||||
this.occupants_view.el.style.flex = "0 0 " + occupants_width + "px";
|
||||
const occupants_width = this.calculateSidebarWidth(element_position, delta);
|
||||
this.sidebar_view.el.style.flex = "0 0 " + occupants_width + "px";
|
||||
}
|
||||
},
|
||||
|
||||
calculateOccupantsWidth(element_position, delta) {
|
||||
calculateSidebarWidth(element_position, delta) {
|
||||
let occupants_width = element_position.width + delta;
|
||||
const room_width = this.el.clientWidth;
|
||||
// keeping display in boundaries
|
||||
|
@ -2120,19 +2120,62 @@ converse.plugins.add('converse-muc-views', {
|
|||
});
|
||||
|
||||
|
||||
_converse.ChatRoomOccupantsView = HTMLView.extend({
|
||||
_converse.MUCInviteModal = _converse.BootstrapModal.extend({
|
||||
id: "muc-invite-modal",
|
||||
|
||||
initialize () {
|
||||
_converse.BootstrapModal.prototype.initialize.apply(this, arguments);
|
||||
this.listenTo(this.model, 'change', this.render);
|
||||
this.initInviteWidget();
|
||||
},
|
||||
|
||||
toHTML () {
|
||||
return tpl_muc_invite_modal(Object.assign(
|
||||
this.model.toJSON(), {
|
||||
'submitInviteForm': ev => this.submitInviteForm(ev)
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
initInviteWidget () {
|
||||
if (this.invite_auto_complete) {
|
||||
this.invite_auto_complete.destroy();
|
||||
}
|
||||
const list = _converse.roster.map(i => ({'label': i.getDisplayName(), 'value': i.get('jid')}));
|
||||
const el = this.el.querySelector('.suggestion-box').parentElement;
|
||||
this.invite_auto_complete = new _converse.AutoComplete(el, {
|
||||
'min_chars': 1,
|
||||
'list': list
|
||||
});
|
||||
},
|
||||
|
||||
submitInviteForm (ev) {
|
||||
ev.preventDefault();
|
||||
// TODO: Add support for sending an invite to multiple JIDs
|
||||
const data = new FormData(ev.target);
|
||||
const jid = data.get('invitee_jids');
|
||||
const reason = data.get('reason');
|
||||
if (u.isValidJID(jid)) {
|
||||
// TODO: Create and use API here
|
||||
this.chatroomview.model.directInvite(jid, reason);
|
||||
this.modal.hide();
|
||||
} else {
|
||||
this.model.set({'invalid_invite_jid': true});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
_converse.MUCSidebar = HTMLView.extend({
|
||||
tagName: 'div',
|
||||
className: 'occupants col-md-3 col-4',
|
||||
|
||||
async initialize () {
|
||||
this.chatroomview = this.model.chatroomview;
|
||||
this.listenTo(this.model, 'add', this.maybeRenderInviteWidget);
|
||||
this.listenTo(this.model, 'add', this.render);
|
||||
this.listenTo(this.model, 'remove', this.render);
|
||||
this.listenTo(this.model, 'change', this.render);
|
||||
this.listenTo(this.model, 'change:affiliation', this.maybeRenderInviteWidget);
|
||||
this.listenTo(this.chatroomview.model.features, 'change', this.render);
|
||||
this.listenTo(this.chatroomview.model.features, 'change:open', this.renderInviteWidget);
|
||||
this.listenTo(this.chatroomview.model, 'change:hidden_occupants', this.setVisibility);
|
||||
this.render();
|
||||
await this.model.fetched;
|
||||
|
@ -2141,21 +2184,16 @@ converse.plugins.add('converse-muc-views', {
|
|||
toHTML () {
|
||||
return tpl_muc_sidebar(
|
||||
Object.assign(this.chatroomview.model.toJSON(), {
|
||||
'allow_muc_invitations': _converse.allow_muc_invitations,
|
||||
'features': this.chatroomview.model.features,
|
||||
'label_occupants': __('Participants'),
|
||||
'occupants': this.model.models
|
||||
'occupants': this.model.models,
|
||||
'invitesAllowed': () => this.invitesAllowed(),
|
||||
'showInviteModal': ev => this.showInviteModal(ev)
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
afterRender () {
|
||||
if (_converse.allow_muc_invitations) {
|
||||
// TODO: the invite widget needs to be rendered via a directive
|
||||
_converse.api.waitUntil('rosterContactsFetched').then(() => this.renderInviteWidget());
|
||||
}
|
||||
this.setVisibility();
|
||||
this.setOccupantsHeight();
|
||||
},
|
||||
|
||||
setVisibility () {
|
||||
|
@ -2167,34 +2205,18 @@ converse.plugins.add('converse-muc-views', {
|
|||
}
|
||||
},
|
||||
|
||||
maybeRenderInviteWidget (occupant) {
|
||||
if (occupant.get('jid') === _converse.bare_jid) {
|
||||
this.renderInviteWidget();
|
||||
showInviteModal (ev) {
|
||||
ev.preventDefault();
|
||||
if (this.muc_invite_modal === undefined) {
|
||||
this.muc_invite_modal = new _converse.MUCInviteModal({'model': new Model()});
|
||||
// TODO: remove once we have API for sending direct invite
|
||||
this.muc_invite_modal.chatroomview = this.chatroomview;
|
||||
}
|
||||
},
|
||||
|
||||
renderInviteWidget () {
|
||||
// TODO: this needs to be rendered inside muc_sidebar.js
|
||||
const widget = this.el.querySelector('.room-invite');
|
||||
if (this.shouldInviteWidgetBeShown()) {
|
||||
if (widget === null) {
|
||||
const heading = this.el.querySelector('.occupants-heading');
|
||||
heading.insertAdjacentHTML(
|
||||
'afterend',
|
||||
tpl_chatroom_invite({
|
||||
'error_message': null,
|
||||
'label_invitation': __('Invite'),
|
||||
})
|
||||
);
|
||||
this.initInviteWidget();
|
||||
}
|
||||
} else if (widget !== null) {
|
||||
widget.remove();
|
||||
}
|
||||
return this;
|
||||
this.muc_invite_modal.show(ev);
|
||||
},
|
||||
|
||||
setOccupantsHeight () {
|
||||
// TODO: remove the features section in sidebar and then this as well
|
||||
const el = this.el.querySelector('.chatroom-features');
|
||||
if (el) {
|
||||
this.el.querySelector('.occupant-list').style.cssText =
|
||||
|
@ -2202,74 +2224,12 @@ converse.plugins.add('converse-muc-views', {
|
|||
}
|
||||
},
|
||||
|
||||
promptForInvite (suggestion) {
|
||||
let reason = '';
|
||||
if (!_converse.auto_join_on_invite) {
|
||||
reason = prompt(
|
||||
__('You are about to invite %1$s to the groupchat "%2$s". '+
|
||||
'You may optionally include a message, explaining the reason for the invitation.',
|
||||
suggestion.text.label, this.chatroomview.model.getDisplayName())
|
||||
);
|
||||
}
|
||||
if (reason !== null) {
|
||||
this.chatroomview.model.directInvite(suggestion.text.value, reason);
|
||||
}
|
||||
const form = this.el.querySelector('.room-invite form'),
|
||||
input = form.querySelector('.invited-contact'),
|
||||
error = form.querySelector('.error');
|
||||
if (error !== null) {
|
||||
error.parentNode.removeChild(error);
|
||||
}
|
||||
input.value = '';
|
||||
},
|
||||
|
||||
inviteFormSubmitted (evt) {
|
||||
evt.preventDefault();
|
||||
const el = evt.target.querySelector('input.invited-contact');
|
||||
const jid = el.value;
|
||||
if (u.isValid(jid)) {
|
||||
this.promptForInvite({
|
||||
'target': el,
|
||||
'text': {'label': jid, 'value': jid}}
|
||||
);
|
||||
} else {
|
||||
evt.target.outerHTML = tpl_chatroom_invite({
|
||||
'error_message': __('Please enter a valid XMPP address'),
|
||||
'label_invitation': __('Invite'),
|
||||
});
|
||||
this.initInviteWidget();
|
||||
}
|
||||
},
|
||||
|
||||
shouldInviteWidgetBeShown () {
|
||||
invitesAllowed () {
|
||||
return _converse.allow_muc_invitations &&
|
||||
(this.chatroomview.model.features.get('open') ||
|
||||
this.chatroomview.model.getOwnAffiliation() === "owner"
|
||||
);
|
||||
},
|
||||
|
||||
initInviteWidget () {
|
||||
const form = this.el.querySelector('.room-invite form');
|
||||
if (form === null) {
|
||||
return;
|
||||
}
|
||||
form.addEventListener('submit', this.inviteFormSubmitted.bind(this), false);
|
||||
const list = _converse.roster.map(i => ({'label': i.getDisplayName(), 'value': i.get('jid')}));
|
||||
const el = this.el.querySelector('.suggestion-box').parentElement;
|
||||
|
||||
if (this.invite_auto_complete) {
|
||||
this.invite_auto_complete.destroy();
|
||||
}
|
||||
this.invite_auto_complete = new _converse.AutoComplete(el, {
|
||||
'min_chars': 1,
|
||||
'list': list
|
||||
});
|
||||
this.invite_auto_complete.on('suggestion-box-selectcomplete', ev => this.promptForInvite(ev));
|
||||
this.invite_auto_complete.on('suggestion-box-open', () => {
|
||||
this.invite_auto_complete.ul.setAttribute('style', `max-height: calc(${this.el.offsetHeight}px - 80px);`);
|
||||
});
|
||||
},
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
},
|
||||
"gitHead": "9641dcdc820e029b05930479c242d2b707bbe8e2",
|
||||
"devDependencies": {
|
||||
"skeletor.js": "skeletorjs/skeletor#29a6d8f707076e865133b8f36f07c76ba4b4b582",
|
||||
"skeletor.js": "skeletorjs/skeletor#9a4487496bd2810b2f0847acbca136333cf9cfb0",
|
||||
"backbone": "1.4",
|
||||
"backbone.browserStorage": "conversejs/backbone.browserStorage#674ba3aa0e4d0f0b0dcac48fcc7dea531012828f",
|
||||
"filesize": "^4.1.2",
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
<div class="suggestion-box room-invite">
|
||||
<form>
|
||||
{[ if (o.error_message) { ]} <div class="error error-feedback">{{{o.error_message}}}</div> {[ } ]}
|
||||
<div class="form-group">
|
||||
<input class="form-control invited-contact suggestion-box__input"
|
||||
placeholder="{{{o.label_invitation}}}"
|
||||
type="text"/>
|
||||
<span class="suggestion-box__additions visually-hidden" role="status" aria-live="assertive" aria-relevant="additions"></span>
|
||||
</div>
|
||||
</form>
|
||||
<ul class="suggestion-box__results suggestion-box__results--below" hidden=""></ul>
|
||||
</div>
|
46
src/templates/muc_invite_modal.js
Normal file
46
src/templates/muc_invite_modal.js
Normal file
|
@ -0,0 +1,46 @@
|
|||
import { html } from "lit-html";
|
||||
import { __ } from '@converse/headless/i18n';
|
||||
import { modal_header_close_button } from "./buttons"
|
||||
|
||||
const i18n_invite = __('Invite');
|
||||
const i18n_invite_heading = __('Invite someone to this groupchat');
|
||||
const error_message = __('Please enter a valid XMPP address');
|
||||
const i18n_invite_label = __('XMPP Address');
|
||||
const i18n_reason = __('Optional reason for the invitation');
|
||||
|
||||
|
||||
export default (o) => html`
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="add-chatroom-modal-label">${i18n_invite_heading}</h5>
|
||||
${modal_header_close_button}
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<span class="modal-alert"></span>
|
||||
<div class="suggestion-box room-invite">
|
||||
<form @submit=${o.submitInviteForm}>
|
||||
<div class="form-group">
|
||||
<label class="clearfix" for="invitee_jids">${i18n_invite_label}:</label>
|
||||
${ o.invalid_invite_jid ? html`<div class="error error-feedback">${error_message}</div>` : '' }
|
||||
<input class="form-control suggestion-box__input"
|
||||
required="required"
|
||||
name="invitee_jids"
|
||||
id="invitee_jids"
|
||||
type="text"/>
|
||||
<span class="suggestion-box__additions visually-hidden" role="status" aria-live="assertive" aria-relevant="additions"></span>
|
||||
<ul class="suggestion-box__results suggestion-box__results--below" hidden=""></ul>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>${i18n_reason}:</label>
|
||||
<textarea class="form-control" name="reason"></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary">${i18n_invite}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -20,6 +20,7 @@ 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');
|
||||
|
@ -32,6 +33,7 @@ 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_participants = __('Participants');
|
||||
const i18n_password = __('Password protected')
|
||||
const i18n_password_hint = __('This groupchat requires a password before entry');
|
||||
const i18n_persistent = __('Persistent');
|
||||
|
@ -77,11 +79,27 @@ const tpl_features = (o) => html`
|
|||
</div>
|
||||
`;
|
||||
|
||||
const invite_button = (o) => {
|
||||
if (o.invitesAllowed()) {
|
||||
return html`
|
||||
<a class="fa fa-user-plus"
|
||||
title="${i18n_invite_hint}"
|
||||
@click=${o.showInviteModal}
|
||||
data-toggle="modal"
|
||||
data-target="#muc-invite-modal"></a>`;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default (o) => html`
|
||||
<div class="occupants-header">
|
||||
<i class="hide-occupants fa fa-times"></i>
|
||||
<p class="occupants-heading">${o.label_occupants}</p>
|
||||
<div class="occupants-header--title">
|
||||
<span class="occupants-heading">${i18n_participants}</span>
|
||||
${ invite_button(o) }
|
||||
</div>
|
||||
</div>
|
||||
<div class="dragresize dragresize-occupants-left"></div>
|
||||
<ul class="occupant-list">
|
||||
|
|
Loading…
Reference in New Issue
Block a user