Commit e8536ebc authored by JC Brand's avatar JC Brand

Move converse-muc-views plugin into own folder

parent 2b6c56f1
...@@ -22,7 +22,7 @@ import "./plugins/dragresize.js"; // Allows chat boxes to be resized b ...@@ -22,7 +22,7 @@ import "./plugins/dragresize.js"; // Allows chat boxes to be resized b
import "./plugins/fullscreen.js"; import "./plugins/fullscreen.js";
import "./plugins/mam-views.js"; import "./plugins/mam-views.js";
import "./plugins/minimize.js"; // Allows chat boxes to be minimized import "./plugins/minimize.js"; // Allows chat boxes to be minimized
import "./plugins/muc-views.js"; // Views related to MUC import "./plugins/muc-views/index.js"; // Views related to MUC
import "./plugins/headlines-view.js"; import "./plugins/headlines-view.js";
import "./plugins/notifications.js"; import "./plugins/notifications.js";
import "./plugins/omemo.js"; import "./plugins/omemo.js";
......
import { _converse, api } from "@converse/headless/core";
export default {
/**
* The "roomviews" namespace groups methods relevant to chatroom
* (aka groupchats) views.
*
* @namespace _converse.api.roomviews
* @memberOf _converse.api
*/
roomviews: {
/**
* Retrieves a groupchat (aka chatroom) view. The chat should already be open.
*
* @method _converse.api.roomviews.get
* @param {String|string[]} name - e.g. 'coven@conference.shakespeare.lit' or
* ['coven@conference.shakespeare.lit', 'cave@conference.shakespeare.lit']
* @returns {View} View representing the groupchat
*
* @example
* // To return a single view, provide the JID of the groupchat
* const view = _converse.api.roomviews.get('coven@conference.shakespeare.lit');
*
* @example
* // To return an array of views, provide an array of JIDs:
* const views = _converse.api.roomviews.get(['coven@conference.shakespeare.lit', 'cave@conference.shakespeare.lit']);
*
* @example
* // To return views of all open groupchats, call the method without any parameters::
* const views = _converse.api.roomviews.get();
*
*/
get (jids) {
if (Array.isArray(jids)) {
const views = api.chatviews.get(jids);
return views.filter(v => v.model.get('type') === _converse.CHATROOMS_TYPE)
} else {
const view = api.chatviews.get(jids);
if (view.model.get('type') === _converse.CHATROOMS_TYPE) {
return view;
} else {
return null;
}
}
},
/**
* Lets you close open chatrooms.
*
* You can call this method without any arguments to close
* all open chatrooms, or you can specify a single JID or
* an array of JIDs.
*
* @method _converse.api.roomviews.close
* @param {(String[]|String)} jids The JID or array of JIDs of the chatroom(s)
* @returns { Promise } - Promise which resolves once the views have been closed.
*/
close (jids) {
let views;
if (jids === undefined) {
views = _converse.chatboxviews;
} else if (typeof jids === 'string') {
views = [_converse.chatboxviews.get(jids)].filter(v => v);
} else if (Array.isArray(jids)) {
views = jids.map(jid => _converse.chatboxviews.get(jid));
}
return Promise.all(views.map(v => (v.is_chatroom && v.model && v.close())))
}
}
}
import log from "@converse/headless/log";
import tpl_muc_config_form from "templates/muc_config_form.js";
import { View } from '@converse/skeletor/src/view.js';
import { __ } from 'i18n';
import { api, converse } from "@converse/headless/core";
const { sizzle } = converse.env;
const u = converse.env.utils;
const MUCConfigForm = View.extend({
className: 'chatroom-form-container muc-config-form',
initialize (attrs) {
this.chatroomview = attrs.chatroomview;
this.listenTo(this.chatroomview.model.features, 'change:passwordprotected', this.render);
this.listenTo(this.chatroomview.model.features, 'change:config_stanza', this.render);
this.render();
},
toHTML () {
const stanza = u.toStanza(this.model.get('config_stanza'));
const whitelist = api.settings.get('roomconfig_whitelist');
let fields = sizzle('field', stanza);
if (whitelist.length) {
fields = fields.filter(f => whitelist.includes(f.getAttribute('var')));
}
const password_protected = this.model.features.get('passwordprotected');
const options = {
'new_password': !password_protected,
'fixed_username': this.model.get('jid')
};
return tpl_muc_config_form({
'closeConfigForm': ev => this.closeConfigForm(ev),
'fields': fields.map(f => u.xForm2webForm(f, stanza, options)),
'instructions': stanza.querySelector('instructions')?.textContent,
'submitConfigForm': ev => this.submitConfigForm(ev),
'title': stanza.querySelector('title')?.textContent
});
},
async submitConfigForm (ev) {
ev.preventDefault();
const inputs = sizzle(':input:not([type=button]):not([type=submit])', ev.target);
const config_array = inputs.map(u.webForm2xForm).filter(f => f);
try {
await this.model.sendConfiguration(config_array);
} catch (e) {
log.error(e);
const message =
__("Sorry, an error occurred while trying to submit the config form.") + " " +
__("Check your browser's developer console for details.");
api.alert('error', __('Error'), message);
}
await this.model.refreshDiscoInfo();
this.chatroomview.closeForm();
},
closeConfigForm (ev) {
ev.preventDefault();
this.chatroomview.closeForm();
}
});
export default MUCConfigForm
/**
* @module converse-muc-views
* @copyright 2020, the Converse.js contributors
* @description XEP-0045 Multi-User Chat Views
* @license Mozilla Public License (MPLv2)
*/
import '../../components/muc-sidebar';
import '../chatview/index.js';
import '../modal.js';
import '@converse/headless/utils/muc';
import ChatRoomViewMixin from './muc.js';
import MUCConfigForm from './config-form.js';
import MUCPasswordForm from './password-form.js';
import log from '@converse/headless/log';
import muc_api from './api.js';
import { RoomsPanel, RoomsPanelViewMixin } from './rooms-panel.js';
import { api, converse, _converse } from '@converse/headless/core';
const { Strophe } = converse.env;
function setMUCDomain (domain, controlboxview) {
controlboxview.getRoomsPanel().model.save('muc_domain', Strophe.getDomainFromJid(domain));
}
function setMUCDomainFromDisco (controlboxview) {
/* Check whether service discovery for the user's domain
* returned MUC information and use that to automatically
* set the MUC domain in the "Add groupchat" modal.
*/
function featureAdded (feature) {
if (!feature) {
return;
}
if (feature.get('var') === Strophe.NS.MUC) {
feature.entity.getIdentity('conference', 'text').then(identity => {
if (identity) {
setMUCDomain(feature.get('from'), controlboxview);
}
});
}
}
api.waitUntil('discoInitialized')
.then(() => {
api.listen.on('serviceDiscovered', featureAdded);
// Features could have been added before the controlbox was
// initialized. We're only interested in MUC
_converse.disco_entities.each(entity => featureAdded(entity.features.findWhere({ 'var': Strophe.NS.MUC })));
})
.catch(e => log.error(e));
}
function fetchAndSetMUCDomain (controlboxview) {
if (controlboxview.model.get('connected')) {
if (!controlboxview.getRoomsPanel().model.get('muc_domain')) {
if (api.settings.get('muc_domain') === undefined) {
setMUCDomainFromDisco(controlboxview);
} else {
setMUCDomain(api.settings.get('muc_domain'), controlboxview);
}
}
}
}
function openChatRoomFromURIClicked (ev) {
ev.preventDefault();
api.rooms.open(ev.target.href);
}
async function addView (model) {
const views = _converse.chatboxviews;
if (!views.get(model.get('id')) && model.get('type') === _converse.CHATROOMS_TYPE && model.isValid()) {
await model.initialized;
return views.add(model.get('id'), new _converse.ChatRoomView({ model }));
}
}
converse.plugins.add('converse-muc-views', {
/* Dependencies are other plugins which might be
* overridden or relied upon, and therefore need to be loaded before
* this plugin. They are "optional" because they might not be
* available, in which case any overrides applicable to them will be
* ignored.
*
* NB: These plugins need to have already been loaded via require.js.
*
* It's possible to make these dependencies "non-optional".
* If the setting "strict_plugin_dependencies" is set to true,
* an error will be raised if the plugin is not found.
*/
dependencies: ['converse-autocomplete', 'converse-modal', 'converse-controlbox', 'converse-chatview'],
overrides: {
ControlBoxView: {
renderControlBoxPane () {
this.__super__.renderControlBoxPane.apply(this, arguments);
if (api.settings.get('allow_muc')) {
this.renderRoomsPanel();
}
}
}
},
initialize () {
const { _converse } = this;
api.promises.add(['roomsPanelRendered']);
// Configuration values for this plugin
// ====================================
// Refer to docs/source/configuration.rst for explanations of these
// configuration settings.
api.settings.extend({
'auto_list_rooms': false,
'cache_muc_messages': true,
'locked_muc_nickname': false,
'modtools_disable_query': [],
'modtools_disable_assign': false,
'muc_disable_slash_commands': false,
'muc_mention_autocomplete_filter': 'contains',
'muc_mention_autocomplete_min_chars': 0,
'muc_mention_autocomplete_show_avatar': true,
'muc_roomid_policy': null,
'muc_roomid_policy_hint': null,
'roomconfig_whitelist': [],
'show_retraction_warning': true,
'visible_toolbar_buttons': {
'toggle_occupants': true
}
});
_converse.MUCConfigForm = MUCConfigForm;
_converse.MUCPasswordForm = MUCPasswordForm;
_converse.ChatRoomView = _converse.ChatBoxView.extend(ChatRoomViewMixin);
_converse.RoomsPanel = RoomsPanel;
_converse.ControlBoxView && Object.assign(_converse.ControlBoxView.prototype, RoomsPanelViewMixin);
Object.assign(_converse.api, muc_api);
/************************ BEGIN Event Handlers ************************/
api.listen.on('chatBoxViewsInitialized', () => {
_converse.chatboxviews.delegate('click', 'a.open-chatroom', openChatRoomFromURIClicked);
_converse.chatboxes.on('add', addView);
});
api.listen.on('clearSession', () => {
const view = _converse.chatboxviews.get('controlbox');
if (view && view.roomspanel) {
view.roomspanel.model.destroy();
view.roomspanel.remove();
delete view.roomspanel;
}
});
api.listen.on('controlBoxInitialized', view => {
if (!api.settings.get('allow_muc')) {
return;
}
fetchAndSetMUCDomain(view);
view.model.on('change:connected', () => fetchAndSetMUCDomain(view));
});
/************************ END Event Handlers ************************/
}
});
import tpl_muc_password_form from "templates/muc_password_form.js";
import { View } from '@converse/skeletor/src/view.js';
const MUCPasswordForm = View.extend({
className: 'chatroom-form-container muc-password-form',
initialize (attrs) {
this.chatroomview = attrs.chatroomview;
this.listenTo(this.model, 'change:validation_message', this.render);
this.render();
},
toHTML () {
return tpl_muc_password_form({
'jid': this.model.get('jid'),
'submitPassword': ev => this.submitPassword(ev),
'validation_message': this.model.get('validation_message')
});
},
submitPassword (ev) {
ev.preventDefault();
const password = this.el.querySelector('input[type=password]').value;
this.chatroomview.model.join(this.chatroomview.model.get('nick'), password);
this.model.set('validation_message', null);
}
});
export default MUCPasswordForm;
import AddMUCModal from 'modals/add-muc.js';
import tpl_room_panel from 'templates/room_panel.js';
import { View } from '@converse/skeletor/src/view.js';
import MUCListModal from 'modals/muc-list.js';
import { _converse, api, converse } from '@converse/headless/core';
import { __ } from 'i18n';
const u = converse.env.utils;
/**
* View which renders MUC section of the control box.
* @class
* @namespace _converse.RoomsPanel
* @memberOf _converse
*/
export const RoomsPanel = View.extend({
tagName: 'div',
className: 'controlbox-section',
id: 'chatrooms',
events: {
'click a.controlbox-heading__btn.show-add-muc-modal': 'showAddRoomModal',
'click a.controlbox-heading__btn.show-list-muc-modal': 'showMUCListModal'
},
toHTML () {
return tpl_room_panel({
'heading_chatrooms': __('Groupchats'),
'title_new_room': __('Add a new groupchat'),
'title_list_rooms': __('Query for groupchats')
});
},
showAddRoomModal (ev) {
api.modal.show(AddMUCModal, { 'model': this.model }, ev);
},
showMUCListModal (ev) {
api.modal.show(MUCListModal, { 'model': this.model }, ev);
}
});
/**
* Mixin which adds the ability to a ControlBox to render a list of open groupchats
* @mixin
*/
export const RoomsPanelViewMixin = {
renderRoomsPanel () {
if (this.roomspanel && u.isInDOM(this.roomspanel.el)) {
return this.roomspanel;
}
const id = `converse.roomspanel${_converse.bare_jid}`;
this.roomspanel = new _converse.RoomsPanel({
'model': new (_converse.RoomsPanelModel.extend({
id,
'browserStorage': _converse.createStore(id)
}))()
});
this.roomspanel.model.fetch();
this.el.querySelector('.controlbox-pane').insertAdjacentElement('beforeEnd', this.roomspanel.render().el);
/**
* Triggered once the section of the { @link _converse.ControlBoxView }
* which shows gropuchats has been rendered.
* @event _converse#roomsPanelRendered
* @example _converse.api.listen.on('roomsPanelRendered', () => { ... });
*/
api.trigger('roomsPanelRendered');
return this.roomspanel;
},
getRoomsPanel () {
if (this.roomspanel && u.isInDOM(this.roomspanel.el)) {
return this.roomspanel;
} else {
return this.renderRoomsPanel();
}
}
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment