Componentize the chat headings
This commit is contained in:
parent
906fa93812
commit
a8a2bb4681
@ -359,7 +359,7 @@
|
||||
color: white;
|
||||
|
||||
&.muc-bottom-panel--muted {
|
||||
height: 8em;
|
||||
height: 4em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
@ -13,8 +13,7 @@ async function openModtools (_converse, view) {
|
||||
const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
|
||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
||||
bottom_panel.onKeyDown(enter);
|
||||
await u.waitUntil(() => view.showModeratorToolsModal.calls.count());
|
||||
const modal = _converse.api.modal.get('converse-modtools-modal');
|
||||
const modal = await u.waitUntil(() => _converse.api.modal.get('converse-modtools-modal'));
|
||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||
return modal;
|
||||
}
|
||||
@ -24,7 +23,6 @@ describe("The groupchat moderator tool", function () {
|
||||
it("allows you to set affiliations and roles",
|
||||
mock.initConverse([], {}, async function (done, _converse) {
|
||||
|
||||
spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
|
||||
const muc_jid = 'lounge@montague.lit';
|
||||
|
||||
let members = [
|
||||
@ -143,7 +141,6 @@ describe("The groupchat moderator tool", function () {
|
||||
it("allows you to filter affiliation search results",
|
||||
mock.initConverse([], {}, async function (done, _converse) {
|
||||
|
||||
spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
|
||||
const muc_jid = 'lounge@montague.lit';
|
||||
const members = [
|
||||
{'jid': 'hag66@shakespeare.lit', 'nick': 'witch', 'affiliation': 'member'},
|
||||
@ -197,11 +194,9 @@ describe("The groupchat moderator tool", function () {
|
||||
it("allows you to filter role search results",
|
||||
mock.initConverse([], {}, async function (done, _converse) {
|
||||
|
||||
spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
|
||||
const muc_jid = 'lounge@montague.lit';
|
||||
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', []);
|
||||
const view = _converse.chatboxviews.get(muc_jid);
|
||||
|
||||
_converse.connection._dataRecv(mock.createRequest(
|
||||
$pres({to: _converse.jid, from: `${muc_jid}/nomorenicks`})
|
||||
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
||||
@ -263,9 +258,8 @@ describe("The groupchat moderator tool", function () {
|
||||
const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
|
||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
||||
bottom_panel.onKeyDown(enter);
|
||||
await u.waitUntil(() => view.showModeratorToolsModal.calls.count());
|
||||
|
||||
const modal = _converse.api.modal.get('converse-modtools-modal');
|
||||
const modal = await u.waitUntil(() => _converse.api.modal.get('converse-modtools-modal'));
|
||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||
|
||||
const tab = modal.el.querySelector('#roles-tab');
|
||||
@ -307,7 +301,6 @@ describe("The groupchat moderator tool", function () {
|
||||
it("shows an error message if a particular affiliation list may not be retrieved",
|
||||
mock.initConverse([], {}, async function (done, _converse) {
|
||||
|
||||
spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
|
||||
const muc_jid = 'lounge@montague.lit';
|
||||
const members = [
|
||||
{'jid': 'hag66@shakespeare.lit', 'nick': 'witch', 'affiliation': 'member'},
|
||||
@ -357,7 +350,6 @@ describe("The groupchat moderator tool", function () {
|
||||
it("shows an error message if a particular affiliation may not be set",
|
||||
mock.initConverse([], {}, async function (done, _converse) {
|
||||
|
||||
spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
|
||||
const muc_jid = 'lounge@montague.lit';
|
||||
const members = [
|
||||
{'jid': 'gower@shakespeare.lit', 'nick': 'gower', 'affiliation': 'member'},
|
||||
@ -422,7 +414,6 @@ describe("The groupchat moderator tool", function () {
|
||||
it("doesn't allow admins to make more admins",
|
||||
mock.initConverse([], {}, async function (done, _converse) {
|
||||
|
||||
spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
|
||||
const muc_jid = 'lounge@montague.lit';
|
||||
const members = [
|
||||
{'jid': 'hag66@shakespeare.lit', 'nick': 'witch', 'affiliation': 'member'},
|
||||
@ -457,7 +448,6 @@ describe("The groupchat moderator tool", function () {
|
||||
it("lets the assignable affiliations and roles be configured via modtools_disable_assign",
|
||||
mock.initConverse([], {}, async function (done, _converse) {
|
||||
|
||||
spyOn(_converse.ChatRoomView.prototype, 'showModeratorToolsModal').and.callThrough();
|
||||
const muc_jid = 'lounge@montague.lit';
|
||||
const members = [{'jid': 'romeo@montague.lit', 'nick': 'romeo', 'affiliation': 'owner'}];
|
||||
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', [], members);
|
||||
@ -467,9 +457,8 @@ describe("The groupchat moderator tool", function () {
|
||||
const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
|
||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
||||
bottom_panel.onKeyDown(enter);
|
||||
await u.waitUntil(() => view.showModeratorToolsModal.calls.count());
|
||||
|
||||
const modal = _converse.api.modal.get('converse-modtools-modal');
|
||||
const modal = await u.waitUntil(() => _converse.api.modal.get('converse-modtools-modal'));
|
||||
const occupant = view.model.occupants.findWhere({'jid': _converse.bare_jid});
|
||||
|
||||
expect(modal.getAssignableAffiliations(occupant)).toEqual(['owner', 'admin', 'member', 'outcast', 'none']);
|
||||
|
@ -1976,8 +1976,7 @@ describe("Groupchats", function () {
|
||||
const view = _converse.chatboxviews.get('lounge@montague.lit');
|
||||
expect(view.model.getOwnAffiliation()).toBe('owner');
|
||||
expect(view.model.features.get('open')).toBe(false);
|
||||
|
||||
expect(view.querySelector('.open-invite-modal')).not.toBe(null);
|
||||
await u.waitUntil(() => view.querySelector('.open-invite-modal'));
|
||||
|
||||
// Members can't invite if the room isn't open
|
||||
view.model.getOwnOccupant().set('affiliation', 'member');
|
||||
@ -2474,7 +2473,7 @@ describe("Groupchats", function () {
|
||||
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.querySelector('.chatbox-title__text').textContent.trim()).toBe('Room');
|
||||
await u.waitUntil(() => view.querySelector('.chatbox-title__text').textContent.trim() === 'Room');
|
||||
|
||||
view.querySelector('.configure-chatroom-button').click();
|
||||
|
||||
|
@ -76,36 +76,11 @@ export default class ChatBottomPanel extends ElementView {
|
||||
}
|
||||
|
||||
emitFocused (ev) {
|
||||
const chatview = _converse.chatboxviews.get(this.getAttribute('jid'));
|
||||
if (chatview.contains(document.activeElement) || chatview.contains(ev.relatedTarget)) {
|
||||
// Something else in this chatbox was already focused
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Triggered when the focus has been moved to a particular chat.
|
||||
* @event _converse#chatBoxFocused
|
||||
* @type { _converse.ChatBoxView | _converse.ChatRoomView }
|
||||
* @example _converse.api.listen.on('chatBoxFocused', (view, event) => { ... });
|
||||
*/
|
||||
api.trigger('chatBoxFocused', this, ev);
|
||||
_converse.chatboxviews.get(this.getAttribute('jid'))?.emitFocused(ev);
|
||||
}
|
||||
|
||||
emitBlurred (ev) {
|
||||
const chatview = _converse.chatboxviews.get(this.getAttribute('jid'));
|
||||
if (!chatview) {
|
||||
return;
|
||||
}
|
||||
if (chatview.contains(document.activeElement) || chatview.contains(ev.relatedTarget)) {
|
||||
// Something else in this chatbox is still focused
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Triggered when the focus has been removed from a particular chat.
|
||||
* @event _converse#chatBoxBlurred
|
||||
* @type { _converse.ChatBoxView | _converse.ChatRoomView }
|
||||
* @example _converse.api.listen.on('chatBoxBlurred', (view, event) => { ... });
|
||||
*/
|
||||
api.trigger('chatBoxBlurred', this, ev);
|
||||
_converse.chatboxviews.get(this.getAttribute('jid'))?.emitBlurred(ev);
|
||||
}
|
||||
|
||||
getToolbarOptions () { // eslint-disable-line class-methods-use-this
|
||||
|
124
src/plugins/chatview/heading.js
Normal file
124
src/plugins/chatview/heading.js
Normal file
@ -0,0 +1,124 @@
|
||||
import UserDetailsModal from 'modals/user-details.js';
|
||||
import debounce from 'lodash/debounce';
|
||||
import tpl_chatbox_head from 'templates/chatbox_head.js';
|
||||
import { ElementView } from '@converse/skeletor/src/element.js';
|
||||
import { __ } from 'i18n';
|
||||
import { _converse, api } from "@converse/headless/core";
|
||||
import { getHeadingDropdownItem, getHeadingStandaloneButton } from 'plugins/chatview/utils.js';
|
||||
import { render } from 'lit-html';
|
||||
|
||||
|
||||
export default class ChatHeading extends ElementView {
|
||||
|
||||
async render () {
|
||||
const tpl = await this.generateHeadingTemplate();
|
||||
render(tpl, this);
|
||||
}
|
||||
|
||||
connectedCallback () {
|
||||
super.connectedCallback();
|
||||
this.model = _converse.chatboxes.get(this.getAttribute('jid'));
|
||||
this.debouncedRender = debounce(this.render, 100);
|
||||
this.listenTo(this.model, 'vcard:change', this.debouncedRender);
|
||||
if (this.model.contact) {
|
||||
this.listenTo(this.model.contact, 'destroy', this.debouncedRender);
|
||||
}
|
||||
this.model.rosterContactAdded?.then(() => {
|
||||
this.listenTo(this.model.contact, 'change:nickname', this.debouncedRender);
|
||||
this.debouncedRender();
|
||||
});
|
||||
this.render();
|
||||
}
|
||||
|
||||
showUserDetailsModal (ev) {
|
||||
ev.preventDefault();
|
||||
api.modal.show(UserDetailsModal, { model: this.model }, ev);
|
||||
}
|
||||
|
||||
close () {
|
||||
_converse.chatboxviews.get(this.getAttribute('jid'))?.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of objects which represent buttons for the chat's header.
|
||||
* @async
|
||||
* @emits _converse#getHeadingButtons
|
||||
*/
|
||||
getHeadingButtons () {
|
||||
const buttons = [
|
||||
{
|
||||
'a_class': 'show-user-details-modal',
|
||||
'handler': ev => this.showUserDetailsModal(ev),
|
||||
'i18n_text': __('Details'),
|
||||
'i18n_title': __('See more information about this person'),
|
||||
'icon_class': 'fa-id-card',
|
||||
'name': 'details',
|
||||
'standalone': api.settings.get('view_mode') === 'overlayed'
|
||||
}
|
||||
];
|
||||
if (!api.settings.get('singleton')) {
|
||||
buttons.push({
|
||||
'a_class': 'close-chatbox-button',
|
||||
'handler': ev => this.close(ev),
|
||||
'i18n_text': __('Close'),
|
||||
'i18n_title': __('Close and end this conversation'),
|
||||
'icon_class': 'fa-times',
|
||||
'name': 'close',
|
||||
'standalone': api.settings.get('view_mode') === 'overlayed'
|
||||
});
|
||||
}
|
||||
/**
|
||||
* *Hook* which allows plugins to add more buttons to a chat's heading.
|
||||
* @event _converse#getHeadingButtons
|
||||
* @example
|
||||
* api.listen.on('getHeadingButtons', (view, buttons) => {
|
||||
* buttons.push({
|
||||
* 'i18n_title': __('Foo'),
|
||||
* 'i18n_text': __('Foo Bar'),
|
||||
* 'handler': ev => alert('Foo!'),
|
||||
* 'a_class': 'toggle-foo',
|
||||
* 'icon_class': 'fa-foo',
|
||||
* 'name': 'foo'
|
||||
* });
|
||||
* return buttons;
|
||||
* });
|
||||
*/
|
||||
const chatview = _converse.chatboxviews.get(this.getAttribute('jid'));
|
||||
if (chatview) {
|
||||
return _converse.api.hook('getHeadingButtons', chatview, buttons);
|
||||
} else {
|
||||
return buttons; // Happens during tests
|
||||
}
|
||||
}
|
||||
|
||||
async generateHeadingTemplate () {
|
||||
const vcard = this.model?.vcard;
|
||||
const vcard_json = vcard ? vcard.toJSON() : {};
|
||||
const i18n_profile = __("The User's Profile Image");
|
||||
const avatar_data = Object.assign(
|
||||
{
|
||||
'alt_text': i18n_profile,
|
||||
'extra_classes': '',
|
||||
'height': 40,
|
||||
'width': 40
|
||||
},
|
||||
vcard_json
|
||||
);
|
||||
const heading_btns = await this.getHeadingButtons();
|
||||
const standalone_btns = heading_btns.filter(b => b.standalone);
|
||||
const dropdown_btns = heading_btns.filter(b => !b.standalone);
|
||||
return tpl_chatbox_head(
|
||||
Object.assign(this.model.toJSON(), {
|
||||
avatar_data,
|
||||
'display_name': this.model.getDisplayName(),
|
||||
'dropdown_btns': dropdown_btns.map(b => getHeadingDropdownItem(b)),
|
||||
'showUserDetailsModal': ev => this.showUserDetailsModal(ev),
|
||||
'standalone_btns': standalone_btns.map(b => getHeadingStandaloneButton(b))
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
api.elements.define('converse-chat-heading', ChatHeading);
|
23
src/plugins/chatview/utils.js
Normal file
23
src/plugins/chatview/utils.js
Normal file
@ -0,0 +1,23 @@
|
||||
import { html } from 'lit-html';
|
||||
|
||||
|
||||
export async function getHeadingDropdownItem (promise_or_data) {
|
||||
const data = await promise_or_data;
|
||||
return html`
|
||||
<a href="#" class="dropdown-item ${data.a_class}" @click=${data.handler} title="${data.i18n_title}"
|
||||
><i class="fa ${data.icon_class}"></i>${data.i18n_text}</a
|
||||
>
|
||||
`;
|
||||
}
|
||||
|
||||
export async function getHeadingStandaloneButton (promise_or_data) {
|
||||
const data = await promise_or_data;
|
||||
return html`
|
||||
<a
|
||||
href="#"
|
||||
class="chatbox-btn ${data.a_class} fa ${data.icon_class}"
|
||||
@click=${data.handler}
|
||||
title="${data.i18n_title}"
|
||||
></a>
|
||||
`;
|
||||
}
|
@ -1,8 +1,7 @@
|
||||
import 'plugins/chatview/heading.js';
|
||||
import 'plugins/chatview/bottom_panel.js';
|
||||
import BaseChatView from 'shared/chat/baseview.js';
|
||||
import UserDetailsModal from 'modals/user-details.js';
|
||||
import tpl_chatbox from 'templates/chatbox.js';
|
||||
import tpl_chatbox_head from 'templates/chatbox_head.js';
|
||||
import { __ } from 'i18n';
|
||||
import { _converse, api, converse } from '@converse/headless/core';
|
||||
import { render } from 'lit-html';
|
||||
@ -36,19 +35,7 @@ export default class ChatView extends BaseChatView {
|
||||
this.listenTo(_converse, 'windowStateChanged', this.onWindowStateChanged);
|
||||
this.listenTo(this.model, 'change:hidden', () => !this.model.get('hidden') && this.afterShown());
|
||||
this.listenTo(this.model, 'change:status', this.onStatusMessageChanged);
|
||||
this.listenTo(this.model, 'vcard:change', this.renderHeading);
|
||||
this.listenTo(this.model.messages, 'change:correcting', this.onMessageCorrecting);
|
||||
|
||||
if (this.model.contact) {
|
||||
this.listenTo(this.model.contact, 'destroy', this.renderHeading);
|
||||
}
|
||||
if (this.model.rosterContactAdded) {
|
||||
this.model.rosterContactAdded.then(() => {
|
||||
this.listenTo(this.model.contact, 'change:nickname', this.renderHeading);
|
||||
this.renderHeading();
|
||||
});
|
||||
}
|
||||
|
||||
this.listenTo(this.model.presence, 'change:show', this.onPresenceChanged);
|
||||
this.render();
|
||||
|
||||
@ -74,7 +61,6 @@ export default class ChatView extends BaseChatView {
|
||||
render(result, this);
|
||||
this.content = this.querySelector('.chat-content');
|
||||
this.help_container = this.querySelector('.chat-content__help');
|
||||
this.renderHeading();
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -93,87 +79,6 @@ export default class ChatView extends BaseChatView {
|
||||
this.hide();
|
||||
}
|
||||
|
||||
showUserDetailsModal (ev) {
|
||||
ev.preventDefault();
|
||||
api.modal.show(UserDetailsModal, { model: this.model }, ev);
|
||||
}
|
||||
|
||||
async generateHeadingTemplate () {
|
||||
const vcard = this.model?.vcard;
|
||||
const vcard_json = vcard ? vcard.toJSON() : {};
|
||||
const i18n_profile = __("The User's Profile Image");
|
||||
const avatar_data = Object.assign(
|
||||
{
|
||||
'alt_text': i18n_profile,
|
||||
'extra_classes': '',
|
||||
'height': 40,
|
||||
'width': 40
|
||||
},
|
||||
vcard_json
|
||||
);
|
||||
const heading_btns = await this.getHeadingButtons();
|
||||
const standalone_btns = heading_btns.filter(b => b.standalone);
|
||||
const dropdown_btns = heading_btns.filter(b => !b.standalone);
|
||||
return tpl_chatbox_head(
|
||||
Object.assign(this.model.toJSON(), {
|
||||
avatar_data,
|
||||
'display_name': this.model.getDisplayName(),
|
||||
'dropdown_btns': dropdown_btns.map(b => this.getHeadingDropdownItem(b)),
|
||||
'showUserDetailsModal': ev => this.showUserDetailsModal(ev),
|
||||
'standalone_btns': standalone_btns.map(b => this.getHeadingStandaloneButton(b))
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of objects which represent buttons for the chat's header.
|
||||
* @async
|
||||
* @emits _converse#getHeadingButtons
|
||||
* @private
|
||||
* @method _converse.ChatBoxView#getHeadingButtons
|
||||
*/
|
||||
getHeadingButtons () {
|
||||
const buttons = [
|
||||
{
|
||||
'a_class': 'show-user-details-modal',
|
||||
'handler': ev => this.showUserDetailsModal(ev),
|
||||
'i18n_text': __('Details'),
|
||||
'i18n_title': __('See more information about this person'),
|
||||
'icon_class': 'fa-id-card',
|
||||
'name': 'details',
|
||||
'standalone': api.settings.get('view_mode') === 'overlayed'
|
||||
}
|
||||
];
|
||||
if (!api.settings.get('singleton')) {
|
||||
buttons.push({
|
||||
'a_class': 'close-chatbox-button',
|
||||
'handler': ev => this.close(ev),
|
||||
'i18n_text': __('Close'),
|
||||
'i18n_title': __('Close and end this conversation'),
|
||||
'icon_class': 'fa-times',
|
||||
'name': 'close',
|
||||
'standalone': api.settings.get('view_mode') === 'overlayed'
|
||||
});
|
||||
}
|
||||
/**
|
||||
* *Hook* which allows plugins to add more buttons to a chat's heading.
|
||||
* @event _converse#getHeadingButtons
|
||||
* @example
|
||||
* api.listen.on('getHeadingButtons', (view, buttons) => {
|
||||
* buttons.push({
|
||||
* 'i18n_title': __('Foo'),
|
||||
* 'i18n_text': __('Foo Bar'),
|
||||
* 'handler': ev => alert('Foo!'),
|
||||
* 'a_class': 'toggle-foo',
|
||||
* 'icon_class': 'fa-foo',
|
||||
* 'name': 'foo'
|
||||
* });
|
||||
* return buttons;
|
||||
* });
|
||||
*/
|
||||
return _converse.api.hook('getHeadingButtons', this, buttons);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a message element, determine wether it should be
|
||||
* marked as a followup message to the previous element.
|
||||
|
54
src/plugins/headlines-view/heading.js
Normal file
54
src/plugins/headlines-view/heading.js
Normal file
@ -0,0 +1,54 @@
|
||||
import ChatHeading from 'plugins/chatview/heading.js';
|
||||
import tpl_chat_head from './templates/chat-head.js';
|
||||
import { __ } from 'i18n';
|
||||
import { _converse, api } from "@converse/headless/core";
|
||||
import { getHeadingDropdownItem, getHeadingStandaloneButton } from 'plugins/chatview/utils.js';
|
||||
|
||||
|
||||
export default class HeadlinesHeading extends ChatHeading {
|
||||
|
||||
async connectedCallback () {
|
||||
super.connectedCallback();
|
||||
this.model = _converse.chatboxes.get(this.getAttribute('jid'));
|
||||
await this.model.initialized;
|
||||
this.render();
|
||||
}
|
||||
|
||||
async generateHeadingTemplate () {
|
||||
const heading_btns = await this.getHeadingButtons();
|
||||
const standalone_btns = heading_btns.filter(b => b.standalone);
|
||||
const dropdown_btns = heading_btns.filter(b => !b.standalone);
|
||||
return tpl_chat_head(
|
||||
Object.assign(this.model.toJSON(), {
|
||||
'display_name': this.model.getDisplayName(),
|
||||
'dropdown_btns': dropdown_btns.map(b => getHeadingDropdownItem(b)),
|
||||
'standalone_btns': standalone_btns.map(b => getHeadingStandaloneButton(b))
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of objects which represent buttons for the headlines header.
|
||||
* @async
|
||||
* @emits _converse#getHeadingButtons
|
||||
* @method HeadlinesHeading#getHeadingButtons
|
||||
*/
|
||||
getHeadingButtons () {
|
||||
const buttons = [];
|
||||
if (!api.settings.get('singleton')) {
|
||||
buttons.push({
|
||||
'a_class': 'close-chatbox-button',
|
||||
'handler': ev => this.close(ev),
|
||||
'i18n_text': __('Close'),
|
||||
'i18n_title': __('Close these announcements'),
|
||||
'icon_class': 'fa-times',
|
||||
'name': 'close',
|
||||
'standalone': api.settings.get('view_mode') === 'overlayed'
|
||||
});
|
||||
}
|
||||
return _converse.api.hook('getHeadingButtons', this, buttons);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
api.elements.define('converse-headlines-heading', HeadlinesHeading);
|
19
src/plugins/headlines-view/templates/headlines.js
Normal file
19
src/plugins/headlines-view/templates/headlines.js
Normal file
@ -0,0 +1,19 @@
|
||||
import '../heading.js';
|
||||
import { html } from "lit-html";
|
||||
|
||||
export default (o) => html`
|
||||
<div class="flyout box-flyout">
|
||||
<converse-dragresize></converse-dragresize>
|
||||
<converse-headlines-heading jid="${o.jid}" class="chat-head chat-head-chatbox row no-gutters"></converse-headlines-heading>
|
||||
<div class="chat-body">
|
||||
<div class="chat-content ${ o.show_send_button ? 'chat-content-sendbutton' : '' }" aria-live="polite">
|
||||
<converse-chat-content
|
||||
class="chat-content__messages"
|
||||
jid="${o.jid}"
|
||||
@scroll=${o.markScrolled}></converse-chat-content>
|
||||
|
||||
<div class="chat-content__help"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
@ -1,7 +1,5 @@
|
||||
import BaseChatView from 'shared/chat/baseview.js';
|
||||
import tpl_chatbox from 'templates/chatbox.js';
|
||||
import tpl_chat_head from './templates/chat-head.js';
|
||||
import { __ } from 'i18n';
|
||||
import tpl_headlines from './templates/headlines.js';
|
||||
import { _converse, api } from '@converse/headless/core';
|
||||
import { render } from 'lit-html';
|
||||
|
||||
@ -47,7 +45,7 @@ class HeadlinesView extends BaseChatView {
|
||||
|
||||
render () {
|
||||
this.setAttribute('id', this.model.get('box_id'));
|
||||
const result = tpl_chatbox(
|
||||
const result = tpl_headlines(
|
||||
Object.assign(this.model.toJSON(), {
|
||||
show_send_button: false,
|
||||
show_toolbar: false,
|
||||
@ -55,7 +53,6 @@ class HeadlinesView extends BaseChatView {
|
||||
);
|
||||
render(result, this);
|
||||
this.content = this.querySelector('.chat-content');
|
||||
this.renderHeading();
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -76,47 +73,6 @@ class HeadlinesView extends BaseChatView {
|
||||
return [];
|
||||
}
|
||||
|
||||
async generateHeadingTemplate () {
|
||||
const heading_btns = await this.getHeadingButtons();
|
||||
const standalone_btns = heading_btns.filter(b => b.standalone);
|
||||
const dropdown_btns = heading_btns.filter(b => !b.standalone);
|
||||
return tpl_chat_head(
|
||||
Object.assign(this.model.toJSON(), {
|
||||
'display_name': this.model.getDisplayName(),
|
||||
'dropdown_btns': dropdown_btns.map(b => this.getHeadingDropdownItem(b)),
|
||||
'standalone_btns': standalone_btns.map(b => this.getHeadingStandaloneButton(b))
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of objects which represent buttons for the headlines header.
|
||||
* @async
|
||||
* @emits _converse#getHeadingButtons
|
||||
* @private
|
||||
* @method _converse.HeadlinesBoxView#getHeadingButtons
|
||||
*/
|
||||
getHeadingButtons () {
|
||||
const buttons = [];
|
||||
if (!api.settings.get('singleton')) {
|
||||
buttons.push({
|
||||
'a_class': 'close-chatbox-button',
|
||||
'handler': ev => this.close(ev),
|
||||
'i18n_text': __('Close'),
|
||||
'i18n_title': __('Close these announcements'),
|
||||
'icon_class': 'fa-times',
|
||||
'name': 'close',
|
||||
'standalone': api.settings.get('view_mode') === 'overlayed'
|
||||
});
|
||||
}
|
||||
return _converse.api.hook('getHeadingButtons', this, buttons);
|
||||
}
|
||||
|
||||
// Override to avoid the methods in converse-chatview
|
||||
renderMessageForm () { // eslint-disable-line class-methods-use-this
|
||||
return;
|
||||
}
|
||||
|
||||
afterShown () { // eslint-disable-line class-methods-use-this
|
||||
return;
|
||||
}
|
||||
|
191
src/plugins/muc-views/heading.js
Normal file
191
src/plugins/muc-views/heading.js
Normal file
@ -0,0 +1,191 @@
|
||||
import ChatHeading from 'plugins/chatview/heading.js';
|
||||
import MUCInviteModal from 'modals/muc-invite.js';
|
||||
import RoomDetailsModal from 'modals/muc-details.js';
|
||||
import debounce from 'lodash/debounce';
|
||||
import tpl_muc_head from './templates/muc_head.js';
|
||||
import { Model } from '@converse/skeletor/src/model.js';
|
||||
import { __ } from 'i18n';
|
||||
import { _converse, api, converse } from "@converse/headless/core";
|
||||
import { getHeadingDropdownItem, getHeadingStandaloneButton } from 'plugins/chatview/utils.js';
|
||||
|
||||
|
||||
export default class MUCHeading extends ChatHeading {
|
||||
|
||||
async connectedCallback () {
|
||||
super.connectedCallback();
|
||||
this.model = _converse.chatboxes.get(this.getAttribute('jid'));
|
||||
this.debouncedRender = debounce(this.render, 100);
|
||||
this.listenTo(this.model, 'change', this.debouncedRender);
|
||||
|
||||
const user_settings = await _converse.api.user.settings.getModel();
|
||||
this.listenTo(user_settings, 'change:mucs_with_hidden_subject', this.debouncedRender);
|
||||
|
||||
await this.model.initialized;
|
||||
this.listenTo(this.model.features, 'change:open', this.debouncedRender);
|
||||
this.model.occupants.forEach(o => this.onOccupantAdded(o));
|
||||
this.listenTo(this.model.occupants, 'add', this.onOccupantAdded);
|
||||
this.listenTo(this.model.occupants, 'change:affiliation', this.onOccupantAffiliationChanged);
|
||||
this.render();
|
||||
}
|
||||
|
||||
onOccupantAdded (occupant) {
|
||||
if (occupant.get('jid') === _converse.bare_jid) {
|
||||
this.debouncedRender();
|
||||
}
|
||||
}
|
||||
|
||||
onOccupantAffiliationChanged (occupant) {
|
||||
if (occupant.get('jid') === _converse.bare_jid) {
|
||||
this.debouncedRender();
|
||||
}
|
||||
}
|
||||
|
||||
showRoomDetailsModal (ev) {
|
||||
ev.preventDefault();
|
||||
api.modal.show(RoomDetailsModal, { 'model': this.model }, ev);
|
||||
}
|
||||
|
||||
showInviteModal (ev) {
|
||||
ev.preventDefault();
|
||||
api.modal.show(MUCInviteModal, { 'model': new Model(), 'chatroomview': this }, ev);
|
||||
}
|
||||
|
||||
toggleTopic (ev) {
|
||||
ev?.preventDefault?.();
|
||||
this.model.toggleSubjectHiddenState();
|
||||
}
|
||||
|
||||
getAndRenderConfigurationForm () {
|
||||
_converse.chatboxviews.get(this.getAttribute('jid'))?.getAndRenderConfigurationForm();
|
||||
}
|
||||
|
||||
showModeratorToolsModal () {
|
||||
_converse.chatboxviews.get(this.getAttribute('jid'))?.showModeratorToolsModal();
|
||||
}
|
||||
|
||||
destroy () {
|
||||
_converse.chatboxviews.get(this.getAttribute('jid'))?.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of objects which represent buttons for the groupchat header.
|
||||
* @emits _converse#getHeadingButtons
|
||||
*/
|
||||
getHeadingButtons (subject_hidden) {
|
||||
const buttons = [];
|
||||
buttons.push({
|
||||
'i18n_text': __('Details'),
|
||||
'i18n_title': __('Show more information about this groupchat'),
|
||||
'handler': ev => this.showRoomDetailsModal(ev),
|
||||
'a_class': 'show-muc-details-modal',
|
||||
'icon_class': 'fa-info-circle',
|
||||
'name': 'details'
|
||||
});
|
||||
|
||||
if (this.model.getOwnAffiliation() === 'owner') {
|
||||
buttons.push({
|
||||
'i18n_text': __('Configure'),
|
||||
'i18n_title': __('Configure this groupchat'),
|
||||
'handler': ev => this.getAndRenderConfigurationForm(ev),
|
||||
'a_class': 'configure-chatroom-button',
|
||||
'icon_class': 'fa-wrench',
|
||||
'name': 'configure'
|
||||
});
|
||||
}
|
||||
|
||||
if (this.model.invitesAllowed()) {
|
||||
buttons.push({
|
||||
'i18n_text': __('Invite'),
|
||||
'i18n_title': __('Invite someone to join this groupchat'),
|
||||
'handler': ev => this.showInviteModal(ev),
|
||||
'a_class': 'open-invite-modal',
|
||||
'icon_class': 'fa-user-plus',
|
||||
'name': 'invite'
|
||||
});
|
||||
}
|
||||
|
||||
const subject = this.model.get('subject');
|
||||
if (subject && subject.text) {
|
||||
buttons.push({
|
||||
'i18n_text': subject_hidden ? __('Show topic') : __('Hide topic'),
|
||||
'i18n_title': subject_hidden
|
||||
? __('Show the topic message in the heading')
|
||||
: __('Hide the topic in the heading'),
|
||||
'handler': ev => this.toggleTopic(ev),
|
||||
'a_class': 'hide-topic',
|
||||
'icon_class': 'fa-minus-square',
|
||||
'name': 'toggle-topic'
|
||||
});
|
||||
}
|
||||
|
||||
const conn_status = this.model.session.get('connection_status');
|
||||
if (conn_status === converse.ROOMSTATUS.ENTERED) {
|
||||
const allowed_commands = this.model.getAllowedCommands();
|
||||
if (allowed_commands.includes('modtools')) {
|
||||
buttons.push({
|
||||
'i18n_text': __('Moderate'),
|
||||
'i18n_title': __('Moderate this groupchat'),
|
||||
'handler': () => this.showModeratorToolsModal(),
|
||||
'a_class': 'moderate-chatroom-button',
|
||||
'icon_class': 'fa-user-cog',
|
||||
'name': 'moderate'
|
||||
});
|
||||
}
|
||||
if (allowed_commands.includes('destroy')) {
|
||||
buttons.push({
|
||||
'i18n_text': __('Destroy'),
|
||||
'i18n_title': __('Remove this groupchat'),
|
||||
'handler': ev => this.destroy(ev),
|
||||
'a_class': 'destroy-chatroom-button',
|
||||
'icon_class': 'fa-trash',
|
||||
'name': 'destroy'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!api.settings.get('singleton')) {
|
||||
buttons.push({
|
||||
'i18n_text': __('Leave'),
|
||||
'i18n_title': __('Leave and close this groupchat'),
|
||||
'handler': async ev => {
|
||||
ev.stopPropagation();
|
||||
const messages = [__('Are you sure you want to leave this groupchat?')];
|
||||
const result = await api.confirm(__('Confirm'), messages);
|
||||
result && this.close(ev);
|
||||
},
|
||||
'a_class': 'close-chatbox-button',
|
||||
'standalone': api.settings.get('view_mode') === 'overlayed',
|
||||
'icon_class': 'fa-sign-out-alt',
|
||||
'name': 'signout'
|
||||
});
|
||||
}
|
||||
const chatview = _converse.chatboxviews.get(this.getAttribute('jid'));
|
||||
if (chatview) {
|
||||
return _converse.api.hook('getHeadingButtons', chatview, buttons);
|
||||
} else {
|
||||
return buttons; // Happens during tests
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the groupchat heading TemplateResult to be rendered.
|
||||
*/
|
||||
async generateHeadingTemplate () {
|
||||
const subject_hidden = await this.model.isSubjectHidden();
|
||||
const heading_btns = await this.getHeadingButtons(subject_hidden);
|
||||
const standalone_btns = heading_btns.filter(b => b.standalone);
|
||||
const dropdown_btns = heading_btns.filter(b => !b.standalone);
|
||||
return tpl_muc_head(
|
||||
Object.assign(this.model.toJSON(), {
|
||||
_converse,
|
||||
subject_hidden,
|
||||
'dropdown_btns': dropdown_btns.map(b => getHeadingDropdownItem(b)),
|
||||
'standalone_btns': standalone_btns.map(b => getHeadingStandaloneButton(b)),
|
||||
'title': this.model.getDisplayName()
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
api.elements.define('converse-muc-heading', MUCHeading);
|
@ -1,14 +1,10 @@
|
||||
import './bottom_panel.js';
|
||||
import './config-form.js';
|
||||
import './password-form.js';
|
||||
import 'shared/autocomplete/index.js';
|
||||
import BaseChatView from 'shared/chat/baseview.js';
|
||||
import MUCInviteModal from 'modals/muc-invite.js';
|
||||
import ModeratorToolsModal from 'modals/moderator-tools.js';
|
||||
import RoomDetailsModal from 'modals/muc-details.js';
|
||||
import log from '@converse/headless/log';
|
||||
import tpl_muc from './templates/muc.js';
|
||||
import tpl_muc_head from './templates/muc_head.js';
|
||||
import tpl_muc_destroyed from './templates/muc_destroyed.js';
|
||||
import tpl_muc_disconnect from './templates/muc_disconnect.js';
|
||||
import tpl_muc_nickname_form from './templates/muc_nickname_form.js';
|
||||
@ -16,7 +12,6 @@ import tpl_spinner from 'templates/spinner.js';
|
||||
import { Model } from '@converse/skeletor/src/model.js';
|
||||
import { __ } from 'i18n';
|
||||
import { _converse, api, converse } from '@converse/headless/core';
|
||||
import { debounce } from 'lodash-es';
|
||||
import { render } from 'lit-html';
|
||||
|
||||
const { sizzle } = converse.env;
|
||||
@ -53,14 +48,12 @@ export default class MUCView extends BaseChatView {
|
||||
this.initDebounced();
|
||||
|
||||
this.listenTo(_converse, 'windowStateChanged', this.onWindowStateChanged);
|
||||
this.listenTo(this.model, 'change', debounce(() => this.renderHeading(), 250));
|
||||
this.listenTo(this.model, 'change:composing_spoiler', this.renderMessageForm);
|
||||
this.listenTo(this.model, 'change:hidden', () => this.afterShown());
|
||||
this.listenTo(this.model, 'change:hidden_occupants', this.onSidebarToggle);
|
||||
this.listenTo(this.model, 'change:minimized', () => this.afterShown());
|
||||
this.listenTo(this.model, 'configurationNeeded', this.getAndRenderConfigurationForm);
|
||||
this.listenTo(this.model, 'show', this.show);
|
||||
this.listenTo(this.model.features, 'change:open', this.renderHeading);
|
||||
this.listenTo(this.model.messages, 'change:correcting', this.onMessageCorrecting);
|
||||
this.listenTo(this.model.session, 'change:connection_status', this.renderAfterTransition);
|
||||
|
||||
@ -73,16 +66,9 @@ export default class MUCView extends BaseChatView {
|
||||
// Need to be registered after render has been called.
|
||||
this.listenTo(this.model, 'change:show_help_messages', this.renderHelpMessages);
|
||||
this.listenTo(this.model.messages, 'add', this.onMessageAdded);
|
||||
|
||||
this.model.occupants.forEach(o => this.onOccupantAdded(o));
|
||||
this.listenTo(this.model.occupants, 'add', this.onOccupantAdded);
|
||||
this.listenTo(this.model.occupants, 'change:affiliation', this.onOccupantAffiliationChanged);
|
||||
this.listenTo(this.model.occupants, 'change:show', this.showJoinOrLeaveNotification);
|
||||
this.listenTo(this.model.occupants, 'remove', this.onOccupantRemoved);
|
||||
|
||||
// Register later due to await
|
||||
const user_settings = await _converse.api.user.settings.getModel();
|
||||
this.listenTo(user_settings, 'change:mucs_with_hidden_subject', this.renderHeading);
|
||||
this.renderAfterTransition();
|
||||
this.model.maybeShow();
|
||||
this.scrollDown();
|
||||
@ -95,7 +81,7 @@ export default class MUCView extends BaseChatView {
|
||||
api.trigger('chatRoomViewInitialized', this);
|
||||
}
|
||||
|
||||
async render () {
|
||||
render () {
|
||||
const sidebar_hidden = !this.shouldShowSidebar();
|
||||
this.setAttribute('id', this.model.get('box_id'));
|
||||
render(
|
||||
@ -126,7 +112,6 @@ export default class MUCView extends BaseChatView {
|
||||
// Render header as late as possible since it's async and we
|
||||
// want the rest of the DOM elements to be available ASAP.
|
||||
// Otherwise e.g. this.notifications is not yet defined when accessed elsewhere.
|
||||
await this.renderHeading();
|
||||
!this.model.get('hidden') && this.show();
|
||||
}
|
||||
|
||||
@ -159,17 +144,6 @@ export default class MUCView extends BaseChatView {
|
||||
.filter(line => this.model.getAllowedCommands().some(c => line.startsWith(c + '<', 9)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the MUC heading if any relevant attributes have changed.
|
||||
* @private
|
||||
* @method _converse.ChatRoomView#renderHeading
|
||||
* @param { _converse.ChatRoom } [item]
|
||||
*/
|
||||
async renderHeading () {
|
||||
const tpl = await this.generateHeadingTemplate();
|
||||
render(tpl, this.querySelector('.chat-head-chatroom'));
|
||||
}
|
||||
|
||||
onStartResizeOccupants (ev) {
|
||||
this.resizing = true;
|
||||
this.addEventListener('mousemove', this.onMouseMove);
|
||||
@ -266,11 +240,6 @@ export default class MUCView extends BaseChatView {
|
||||
modal.show();
|
||||
}
|
||||
|
||||
showRoomDetailsModal (ev) {
|
||||
ev.preventDefault();
|
||||
api.modal.show(RoomDetailsModal, { 'model': this.model }, ev);
|
||||
}
|
||||
|
||||
showChatStateNotification (message) {
|
||||
if (message.get('sender') === 'me') {
|
||||
return;
|
||||
@ -289,139 +258,6 @@ export default class MUCView extends BaseChatView {
|
||||
this.querySelector('.occupants')?.setVisibility();
|
||||
}
|
||||
|
||||
onOccupantAffiliationChanged (occupant) {
|
||||
if (occupant.get('jid') === _converse.bare_jid) {
|
||||
this.renderHeading();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of objects which represent buttons for the groupchat header.
|
||||
* @emits _converse#getHeadingButtons
|
||||
* @private
|
||||
* @method _converse.ChatRoomView#getHeadingButtons
|
||||
*/
|
||||
getHeadingButtons (subject_hidden) {
|
||||
const buttons = [];
|
||||
buttons.push({
|
||||
'i18n_text': __('Details'),
|
||||
'i18n_title': __('Show more information about this groupchat'),
|
||||
'handler': ev => this.showRoomDetailsModal(ev),
|
||||
'a_class': 'show-muc-details-modal',
|
||||
'icon_class': 'fa-info-circle',
|
||||
'name': 'details'
|
||||
});
|
||||
|
||||
if (this.model.getOwnAffiliation() === 'owner') {
|
||||
buttons.push({
|
||||
'i18n_text': __('Configure'),
|
||||
'i18n_title': __('Configure this groupchat'),
|
||||
'handler': ev => this.getAndRenderConfigurationForm(ev),
|
||||
'a_class': 'configure-chatroom-button',
|
||||
'icon_class': 'fa-wrench',
|
||||
'name': 'configure'
|
||||
});
|
||||
}
|
||||
|
||||
if (this.model.invitesAllowed()) {
|
||||
buttons.push({
|
||||
'i18n_text': __('Invite'),
|
||||
'i18n_title': __('Invite someone to join this groupchat'),
|
||||
'handler': ev => this.showInviteModal(ev),
|
||||
'a_class': 'open-invite-modal',
|
||||
'icon_class': 'fa-user-plus',
|
||||
'name': 'invite'
|
||||
});
|
||||
}
|
||||
|
||||
const subject = this.model.get('subject');
|
||||
if (subject && subject.text) {
|
||||
buttons.push({
|
||||
'i18n_text': subject_hidden ? __('Show topic') : __('Hide topic'),
|
||||
'i18n_title': subject_hidden
|
||||
? __('Show the topic message in the heading')
|
||||
: __('Hide the topic in the heading'),
|
||||
'handler': ev => this.toggleTopic(ev),
|
||||
'a_class': 'hide-topic',
|
||||
'icon_class': 'fa-minus-square',
|
||||
'name': 'toggle-topic'
|
||||
});
|
||||
}
|
||||
|
||||
const conn_status = this.model.session.get('connection_status');
|
||||
if (conn_status === converse.ROOMSTATUS.ENTERED) {
|
||||
const allowed_commands = this.model.getAllowedCommands();
|
||||
if (allowed_commands.includes('modtools')) {
|
||||
buttons.push({
|
||||
'i18n_text': __('Moderate'),
|
||||
'i18n_title': __('Moderate this groupchat'),
|
||||
'handler': () => this.showModeratorToolsModal(),
|
||||
'a_class': 'moderate-chatroom-button',
|
||||
'icon_class': 'fa-user-cog',
|
||||
'name': 'moderate'
|
||||
});
|
||||
}
|
||||
if (allowed_commands.includes('destroy')) {
|
||||
buttons.push({
|
||||
'i18n_text': __('Destroy'),
|
||||
'i18n_title': __('Remove this groupchat'),
|
||||
'handler': ev => this.destroy(ev),
|
||||
'a_class': 'destroy-chatroom-button',
|
||||
'icon_class': 'fa-trash',
|
||||
'name': 'destroy'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!api.settings.get('singleton')) {
|
||||
buttons.push({
|
||||
'i18n_text': __('Leave'),
|
||||
'i18n_title': __('Leave and close this groupchat'),
|
||||
'handler': async ev => {
|
||||
ev.stopPropagation();
|
||||
const messages = [__('Are you sure you want to leave this groupchat?')];
|
||||
const result = await api.confirm(__('Confirm'), messages);
|
||||
result && this.close(ev);
|
||||
},
|
||||
'a_class': 'close-chatbox-button',
|
||||
'standalone': api.settings.get('view_mode') === 'overlayed',
|
||||
'icon_class': 'fa-sign-out-alt',
|
||||
'name': 'signout'
|
||||
});
|
||||
}
|
||||
return _converse.api.hook('getHeadingButtons', this, buttons);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the groupchat heading TemplateResult to be rendered.
|
||||
* @private
|
||||
* @method _converse.ChatRoomView#generateHeadingTemplate
|
||||
*/
|
||||
async generateHeadingTemplate () {
|
||||
const subject_hidden = await this.model.isSubjectHidden();
|
||||
const heading_btns = await this.getHeadingButtons(subject_hidden);
|
||||
const standalone_btns = heading_btns.filter(b => b.standalone);
|
||||
const dropdown_btns = heading_btns.filter(b => !b.standalone);
|
||||
return tpl_muc_head(
|
||||
Object.assign(this.model.toJSON(), {
|
||||
_converse,
|
||||
subject_hidden,
|
||||
'dropdown_btns': dropdown_btns.map(b => this.getHeadingDropdownItem(b)),
|
||||
'standalone_btns': standalone_btns.map(b => this.getHeadingStandaloneButton(b)),
|
||||
'title': this.model.getDisplayName()
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
toggleTopic () {
|
||||
this.model.toggleSubjectHiddenState();
|
||||
}
|
||||
|
||||
showInviteModal (ev) {
|
||||
ev.preventDefault();
|
||||
api.modal.show(MUCInviteModal, { 'model': new Model(), 'chatroomview': this }, ev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback method that gets called after the chat has become visible.
|
||||
* @private
|
||||
@ -660,11 +496,6 @@ export default class MUCView extends BaseChatView {
|
||||
u.showElement(container);
|
||||
}
|
||||
|
||||
onOccupantAdded (occupant) {
|
||||
if (occupant.get('jid') === _converse.bare_jid) {
|
||||
this.renderHeading();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Working backwards, get today's most recent join/leave notification
|
||||
|
@ -1,20 +1,22 @@
|
||||
import '../heading.js';
|
||||
import '../bottom_panel.js';
|
||||
import { html } from "lit-html";
|
||||
|
||||
export default (o) => html`
|
||||
<div class="flyout box-flyout">
|
||||
<converse-dragresize></converse-dragresize>
|
||||
<div class="chat-head chat-head-chatroom row no-gutters"></div>
|
||||
<converse-muc-heading jid="${o.model.get('jid')}" class="chat-head chat-head-chatroom row no-gutters"></converse-muc-heading>
|
||||
<div class="chat-body chatroom-body row no-gutters">
|
||||
<div class="chat-area col">
|
||||
<div class="chat-content ${ o.show_send_button ? 'chat-content-sendbutton' : '' }" aria-live="polite">
|
||||
<converse-chat-content
|
||||
class="chat-content__messages"
|
||||
jid=${o.model.get('jid')}
|
||||
jid="${o.model.get('jid')}"
|
||||
@scroll=${o.markScrolled}></converse-chat-content>
|
||||
|
||||
<div class="chat-content__help"></div>
|
||||
</div>
|
||||
<converse-muc-bottom-panel jid=${o.model.get('jid')} class="bottom-panel"></converse-muc-bottom-panel>
|
||||
<converse-muc-bottom-panel jid="${o.model.get('jid')}" class="bottom-panel"></converse-muc-bottom-panel>
|
||||
</div>
|
||||
<div class="disconnect-container hidden"></div>
|
||||
<converse-muc-sidebar class="occupants col-md-3 col-4 ${o.sidebar_hidden ? 'hidden' : ''}"
|
||||
|
@ -14,11 +14,6 @@ export default class BaseChatView extends ElementView {
|
||||
this.debouncedScrollDown = debounce(this.scrollDown, 100);
|
||||
}
|
||||
|
||||
async renderHeading () {
|
||||
const tpl = await this.generateHeadingTemplate();
|
||||
render(tpl, this.querySelector('.chat-head-chatbox'));
|
||||
}
|
||||
|
||||
renderHelpMessages () {
|
||||
render(
|
||||
html`
|
||||
@ -34,18 +29,6 @@ export default class BaseChatView extends ElementView {
|
||||
);
|
||||
}
|
||||
|
||||
async getHeadingStandaloneButton (promise_or_data) { // eslint-disable-line class-methods-use-this
|
||||
const data = await promise_or_data;
|
||||
return html`
|
||||
<a
|
||||
href="#"
|
||||
class="chatbox-btn ${data.a_class} fa ${data.icon_class}"
|
||||
@click=${data.handler}
|
||||
title="${data.i18n_title}"
|
||||
></a>
|
||||
`;
|
||||
}
|
||||
|
||||
hideNewMessagesIndicator () {
|
||||
const new_msgs_indicator = this.querySelector('.new-msgs-indicator');
|
||||
if (new_msgs_indicator !== null) {
|
||||
@ -77,6 +60,34 @@ export default class BaseChatView extends ElementView {
|
||||
this.afterShown();
|
||||
}
|
||||
|
||||
emitBlurred (ev) {
|
||||
if (this.contains(document.activeElement) || this.contains(ev.relatedTarget)) {
|
||||
// Something else in this chatbox is still focused
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Triggered when the focus has been removed from a particular chat.
|
||||
* @event _converse#chatBoxBlurred
|
||||
* @type { _converse.ChatBoxView | _converse.ChatRoomView }
|
||||
* @example _converse.api.listen.on('chatBoxBlurred', (view, event) => { ... });
|
||||
*/
|
||||
api.trigger('chatBoxBlurred', this, ev);
|
||||
}
|
||||
|
||||
emitFocused (ev) {
|
||||
if (this.contains(ev.relatedTarget)) {
|
||||
// Something else in this chatbox was already focused
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Triggered when the focus has been moved to a particular chat.
|
||||
* @event _converse#chatBoxFocused
|
||||
* @type { _converse.ChatBoxView | _converse.ChatRoomView }
|
||||
* @example _converse.api.listen.on('chatBoxFocused', (view, event) => { ... });
|
||||
*/
|
||||
api.trigger('chatBoxFocused', this, ev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scroll to the previously saved scrollTop position, or scroll
|
||||
* down if it wasn't set.
|
||||
@ -123,16 +134,6 @@ export default class BaseChatView extends ElementView {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async getHeadingDropdownItem (promise_or_data) { // eslint-disable-line class-methods-use-this
|
||||
const data = await promise_or_data;
|
||||
return html`
|
||||
<a href="#" class="dropdown-item ${data.a_class}" @click=${data.handler} title="${data.i18n_title}"
|
||||
><i class="fa ${data.icon_class}"></i>${data.i18n_text}</a
|
||||
>
|
||||
`;
|
||||
}
|
||||
|
||||
showNewMessagesIndicator () {
|
||||
u.showElement(this.querySelector('.new-msgs-indicator'));
|
||||
}
|
||||
|
@ -3,17 +3,17 @@ import { html } from "lit-html";
|
||||
export default (o) => html`
|
||||
<div class="flyout box-flyout">
|
||||
<converse-dragresize></converse-dragresize>
|
||||
<div class="chat-head chat-head-chatbox row no-gutters"></div>
|
||||
<converse-chat-heading jid="${o.jid}" class="chat-head chat-head-chatbox row no-gutters"></converse-chat-heading>
|
||||
<div class="chat-body">
|
||||
<div class="chat-content ${ o.show_send_button ? 'chat-content-sendbutton' : '' }" aria-live="polite">
|
||||
<converse-chat-content
|
||||
class="chat-content__messages"
|
||||
jid=${o.jid}
|
||||
jid="${o.jid}"
|
||||
@scroll=${o.markScrolled}></converse-chat-content>
|
||||
|
||||
<div class="chat-content__help"></div>
|
||||
</div>
|
||||
<converse-chat-bottom-panel jid=${o.jid} class="bottom-panel"> </converse-chat-bottom-panel>
|
||||
<converse-chat-bottom-panel jid="${o.jid}" class="bottom-panel"> </converse-chat-bottom-panel>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
Loading…
Reference in New Issue
Block a user