heading.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. import ChatHeading from 'plugins/chatview/heading.js';
  2. import MUCInviteModal from 'modals/muc-invite.js';
  3. import RoomDetailsModal from 'modals/muc-details.js';
  4. import debounce from 'lodash/debounce';
  5. import tpl_muc_head from './templates/muc-head.js';
  6. import { Model } from '@converse/skeletor/src/model.js';
  7. import { __ } from 'i18n';
  8. import { _converse, api, converse } from "@converse/headless/core";
  9. import { showModeratorToolsModal } from './utils.js';
  10. import {
  11. getHeadingDropdownItem,
  12. getHeadingStandaloneButton,
  13. } from 'plugins/chatview/utils.js';
  14. import './styles/muc-head.scss';
  15. export default class MUCHeading extends ChatHeading {
  16. async connectedCallback () {
  17. super.connectedCallback();
  18. this.model = _converse.chatboxes.get(this.getAttribute('jid'));
  19. this.debouncedRender = debounce(this.render, 100);
  20. this.listenTo(this.model, 'change', this.debouncedRender);
  21. const user_settings = await _converse.api.user.settings.getModel();
  22. this.listenTo(user_settings, 'change:mucs_with_hidden_subject', this.debouncedRender);
  23. await this.model.initialized;
  24. this.listenTo(this.model.features, 'change:open', this.debouncedRender);
  25. this.model.occupants.forEach(o => this.onOccupantAdded(o));
  26. this.listenTo(this.model.occupants, 'add', this.onOccupantAdded);
  27. this.listenTo(this.model.occupants, 'change:affiliation', this.onOccupantAffiliationChanged);
  28. this.render();
  29. }
  30. onOccupantAdded (occupant) {
  31. if (occupant.get('jid') === _converse.bare_jid) {
  32. this.debouncedRender();
  33. }
  34. }
  35. onOccupantAffiliationChanged (occupant) {
  36. if (occupant.get('jid') === _converse.bare_jid) {
  37. this.debouncedRender();
  38. }
  39. }
  40. showRoomDetailsModal (ev) {
  41. ev.preventDefault();
  42. api.modal.show(RoomDetailsModal, { 'model': this.model }, ev);
  43. }
  44. showInviteModal (ev) {
  45. ev.preventDefault();
  46. api.modal.show(MUCInviteModal, { 'model': new Model(), 'chatroomview': this }, ev);
  47. }
  48. toggleTopic (ev) {
  49. ev?.preventDefault?.();
  50. this.model.toggleSubjectHiddenState();
  51. }
  52. getAndRenderConfigurationForm () {
  53. this.model.session.set('view', converse.MUC.VIEWS.CONFIG);
  54. }
  55. destroy () {
  56. _converse.chatboxviews.get(this.getAttribute('jid'))?.destroy();
  57. }
  58. /**
  59. * Returns a list of objects which represent buttons for the groupchat header.
  60. * @emits _converse#getHeadingButtons
  61. */
  62. getHeadingButtons (subject_hidden) {
  63. const buttons = [];
  64. buttons.push({
  65. 'i18n_text': __('Details'),
  66. 'i18n_title': __('Show more information about this groupchat'),
  67. 'handler': ev => this.showRoomDetailsModal(ev),
  68. 'a_class': 'show-muc-details-modal',
  69. 'icon_class': 'fa-info-circle',
  70. 'name': 'details'
  71. });
  72. if (this.model.getOwnAffiliation() === 'owner') {
  73. buttons.push({
  74. 'i18n_text': __('Configure'),
  75. 'i18n_title': __('Configure this groupchat'),
  76. 'handler': () => this.getAndRenderConfigurationForm(),
  77. 'a_class': 'configure-chatroom-button',
  78. 'icon_class': 'fa-wrench',
  79. 'name': 'configure'
  80. });
  81. }
  82. if (this.model.invitesAllowed()) {
  83. buttons.push({
  84. 'i18n_text': __('Invite'),
  85. 'i18n_title': __('Invite someone to join this groupchat'),
  86. 'handler': ev => this.showInviteModal(ev),
  87. 'a_class': 'open-invite-modal',
  88. 'icon_class': 'fa-user-plus',
  89. 'name': 'invite'
  90. });
  91. }
  92. const subject = this.model.get('subject');
  93. if (subject && subject.text) {
  94. buttons.push({
  95. 'i18n_text': subject_hidden ? __('Show topic') : __('Hide topic'),
  96. 'i18n_title': subject_hidden
  97. ? __('Show the topic message in the heading')
  98. : __('Hide the topic in the heading'),
  99. 'handler': ev => this.toggleTopic(ev),
  100. 'a_class': 'hide-topic',
  101. 'icon_class': 'fa-minus-square',
  102. 'name': 'toggle-topic'
  103. });
  104. }
  105. const conn_status = this.model.session.get('connection_status');
  106. if (conn_status === converse.ROOMSTATUS.ENTERED) {
  107. const allowed_commands = this.model.getAllowedCommands();
  108. if (allowed_commands.includes('modtools')) {
  109. buttons.push({
  110. 'i18n_text': __('Moderate'),
  111. 'i18n_title': __('Moderate this groupchat'),
  112. 'handler': () => showModeratorToolsModal(this.model),
  113. 'a_class': 'moderate-chatroom-button',
  114. 'icon_class': 'fa-user-cog',
  115. 'name': 'moderate'
  116. });
  117. }
  118. if (allowed_commands.includes('destroy')) {
  119. buttons.push({
  120. 'i18n_text': __('Destroy'),
  121. 'i18n_title': __('Remove this groupchat'),
  122. 'handler': ev => this.destroy(ev),
  123. 'a_class': 'destroy-chatroom-button',
  124. 'icon_class': 'fa-trash',
  125. 'name': 'destroy'
  126. });
  127. }
  128. }
  129. if (!api.settings.get('singleton')) {
  130. buttons.push({
  131. 'i18n_text': __('Leave'),
  132. 'i18n_title': __('Leave and close this groupchat'),
  133. 'handler': async ev => {
  134. ev.stopPropagation();
  135. const messages = [__('Are you sure you want to leave this groupchat?')];
  136. const result = await api.confirm(__('Confirm'), messages);
  137. result && this.close(ev);
  138. },
  139. 'a_class': 'close-chatbox-button',
  140. 'standalone': api.settings.get('view_mode') === 'overlayed',
  141. 'icon_class': 'fa-sign-out-alt',
  142. 'name': 'signout'
  143. });
  144. }
  145. const chatview = _converse.chatboxviews.get(this.getAttribute('jid'));
  146. if (chatview) {
  147. return _converse.api.hook('getHeadingButtons', chatview, buttons);
  148. } else {
  149. return buttons; // Happens during tests
  150. }
  151. }
  152. /**
  153. * Returns the groupchat heading TemplateResult to be rendered.
  154. */
  155. async generateHeadingTemplate () {
  156. const subject_hidden = await this.model.isSubjectHidden();
  157. const heading_btns = await this.getHeadingButtons(subject_hidden);
  158. const standalone_btns = heading_btns.filter(b => b.standalone);
  159. const dropdown_btns = heading_btns.filter(b => !b.standalone);
  160. return tpl_muc_head(
  161. Object.assign(this.model.toJSON(), {
  162. _converse,
  163. subject_hidden,
  164. 'dropdown_btns': dropdown_btns.map(b => getHeadingDropdownItem(b)),
  165. 'standalone_btns': standalone_btns.map(b => getHeadingStandaloneButton(b)),
  166. 'title': this.model.getDisplayName()
  167. })
  168. );
  169. }
  170. }
  171. api.elements.define('converse-muc-heading', MUCHeading);