Create converse-message-form
component
More work on making bottom panel sub-components declarative - Handle auto-completion in the converse-muc-message-form element - Make message limit indicator a component - Rename template
This commit is contained in:
parent
623deac3ec
commit
f3efbba26c
|
@ -25,7 +25,6 @@ module.exports = function(config) {
|
||||||
{ pattern: "node_modules/sinon/pkg/sinon.js", type: 'module' },
|
{ pattern: "node_modules/sinon/pkg/sinon.js", type: 'module' },
|
||||||
{ pattern: "spec/mock.js", type: 'module' },
|
{ pattern: "spec/mock.js", type: 'module' },
|
||||||
|
|
||||||
{ pattern: "spec/emojis.js", type: 'module' },
|
|
||||||
{ pattern: "spec/protocol.js", type: 'module' },
|
{ pattern: "spec/protocol.js", type: 'module' },
|
||||||
{ pattern: "spec/push.js", type: 'module' },
|
{ pattern: "spec/push.js", type: 'module' },
|
||||||
{ pattern: "spec/user-details-modal.js", type: 'module' },
|
{ pattern: "spec/user-details-modal.js", type: 'module' },
|
||||||
|
@ -43,6 +42,7 @@ module.exports = function(config) {
|
||||||
{ pattern: "src/plugins/bookmark-views/tests/bookmarks.js", type: 'module' },
|
{ pattern: "src/plugins/bookmark-views/tests/bookmarks.js", type: 'module' },
|
||||||
{ pattern: "src/plugins/chatview/tests/chatbox.js", type: 'module' },
|
{ pattern: "src/plugins/chatview/tests/chatbox.js", type: 'module' },
|
||||||
{ pattern: "src/plugins/chatview/tests/corrections.js", type: 'module' },
|
{ pattern: "src/plugins/chatview/tests/corrections.js", type: 'module' },
|
||||||
|
{ pattern: "src/plugins/chatview/tests/emojis.js", type: 'module' },
|
||||||
{ pattern: "src/plugins/chatview/tests/http-file-upload.js", type: 'module' },
|
{ pattern: "src/plugins/chatview/tests/http-file-upload.js", type: 'module' },
|
||||||
{ pattern: "src/plugins/chatview/tests/markers.js", type: 'module' },
|
{ pattern: "src/plugins/chatview/tests/markers.js", type: 'module' },
|
||||||
{ pattern: "src/plugins/chatview/tests/me-messages.js", type: 'module' },
|
{ pattern: "src/plugins/chatview/tests/me-messages.js", type: 'module' },
|
||||||
|
|
|
@ -48,8 +48,8 @@ describe("Emojis", function () {
|
||||||
'keyCode': 9,
|
'keyCode': 9,
|
||||||
'key': 'Tab'
|
'key': 'Tab'
|
||||||
}
|
}
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown(tab_event);
|
message_form.onKeyDown(tab_event);
|
||||||
await u.waitUntil(() => view.querySelector('converse-emoji-picker .emoji-search')?.value === ':gri');
|
await u.waitUntil(() => view.querySelector('converse-emoji-picker .emoji-search')?.value === ':gri');
|
||||||
await u.waitUntil(() => sizzle('.emojis-lists__container--search .insert-emoji', view).length === 3, 1000);
|
await u.waitUntil(() => sizzle('.emojis-lists__container--search .insert-emoji', view).length === 3, 1000);
|
||||||
let visible_emojis = sizzle('.emojis-lists__container--search .insert-emoji', view);
|
let visible_emojis = sizzle('.emojis-lists__container--search .insert-emoji', view);
|
||||||
|
@ -89,7 +89,7 @@ describe("Emojis", function () {
|
||||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||||
|
|
||||||
textarea.value = ':use';
|
textarea.value = ':use';
|
||||||
bottom_panel.onKeyDown(tab_event);
|
message_form.onKeyDown(tab_event);
|
||||||
await u.waitUntil(() => u.isVisible(view.querySelector('.emoji-picker__lists')));
|
await u.waitUntil(() => u.isVisible(view.querySelector('.emoji-picker__lists')));
|
||||||
await u.waitUntil(() => input.value === ':use');
|
await u.waitUntil(() => input.value === ':use');
|
||||||
visible_emojis = sizzle('.insert-emoji:not(.hidden)', picker);
|
visible_emojis = sizzle('.insert-emoji:not(.hidden)', picker);
|
||||||
|
@ -115,8 +115,8 @@ describe("Emojis", function () {
|
||||||
'keyCode': 9,
|
'keyCode': 9,
|
||||||
'key': 'Tab'
|
'key': 'Tab'
|
||||||
}
|
}
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown(tab_event);
|
message_form.onKeyDown(tab_event);
|
||||||
await u.waitUntil(() => u.isVisible(view.querySelector('.emoji-picker__lists')));
|
await u.waitUntil(() => u.isVisible(view.querySelector('.emoji-picker__lists')));
|
||||||
|
|
||||||
const picker = view.querySelector('converse-emoji-picker');
|
const picker = view.querySelector('converse-emoji-picker');
|
||||||
|
@ -134,7 +134,7 @@ describe("Emojis", function () {
|
||||||
emoji.click();
|
emoji.click();
|
||||||
await u.waitUntil(() => textarea.value === ':grinning: ');
|
await u.waitUntil(() => textarea.value === ':grinning: ');
|
||||||
textarea.value = ':grinning: :';
|
textarea.value = ':grinning: :';
|
||||||
bottom_panel.onKeyDown(tab_event);
|
message_form.onKeyDown(tab_event);
|
||||||
|
|
||||||
await u.waitUntil(() => input.value === ':');
|
await u.waitUntil(() => input.value === ':');
|
||||||
input.value = ':grimacing';
|
input.value = ':grimacing';
|
||||||
|
@ -167,8 +167,8 @@ describe("Emojis", function () {
|
||||||
'key': 'Tab'
|
'key': 'Tab'
|
||||||
}
|
}
|
||||||
textarea.value = ':';
|
textarea.value = ':';
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown(tab_event);
|
message_form.onKeyDown(tab_event);
|
||||||
await u.waitUntil(() => u.isVisible(view.querySelector('.emoji-picker__lists')));
|
await u.waitUntil(() => u.isVisible(view.querySelector('.emoji-picker__lists')));
|
||||||
const picker = view.querySelector('converse-emoji-picker');
|
const picker = view.querySelector('converse-emoji-picker');
|
||||||
const input = picker.querySelector('.emoji-search');
|
const input = picker.querySelector('.emoji-search');
|
||||||
|
@ -179,7 +179,7 @@ describe("Emojis", function () {
|
||||||
expect(textarea.value).toBe(':100: ');
|
expect(textarea.value).toBe(':100: ');
|
||||||
|
|
||||||
textarea.value = ':';
|
textarea.value = ':';
|
||||||
bottom_panel.onKeyDown(tab_event);
|
message_form.onKeyDown(tab_event);
|
||||||
await u.waitUntil(() => u.isVisible(view.querySelector('.emoji-picker__lists')));
|
await u.waitUntil(() => u.isVisible(view.querySelector('.emoji-picker__lists')));
|
||||||
await u.waitUntil(() => input.value === ':');
|
await u.waitUntil(() => input.value === ':');
|
||||||
input.dispatchEvent(new KeyboardEvent('keydown', tab_event));
|
input.dispatchEvent(new KeyboardEvent('keydown', tab_event));
|
||||||
|
@ -285,8 +285,8 @@ describe("Emojis", function () {
|
||||||
// emojis now renders normally again.
|
// emojis now renders normally again.
|
||||||
const textarea = view.querySelector('textarea.chat-textarea');
|
const textarea = view.querySelector('textarea.chat-textarea');
|
||||||
textarea.value = ':poop: :innocent:';
|
textarea.value = ':poop: :innocent:';
|
||||||
const bottom_panel = view.querySelector('converse-chat-bottom-panel');
|
const message_form = view.querySelector('converse-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
|
@ -296,7 +296,7 @@ describe("Emojis", function () {
|
||||||
await u.waitUntil(() => view.querySelector(last_msg_sel).textContent === '💩 😇');
|
await u.waitUntil(() => view.querySelector(last_msg_sel).textContent === '💩 😇');
|
||||||
|
|
||||||
expect(textarea.value).toBe('');
|
expect(textarea.value).toBe('');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
keyCode: 38 // Up arrow
|
keyCode: 38 // Up arrow
|
||||||
});
|
});
|
||||||
|
@ -306,7 +306,7 @@ describe("Emojis", function () {
|
||||||
await u.waitUntil(() => u.hasClass('correcting', view.querySelector(sel)), 500);
|
await u.waitUntil(() => u.hasClass('correcting', view.querySelector(sel)), 500);
|
||||||
const edited_text = textarea.value += 'This is no longer an emoji-only message';
|
const edited_text = textarea.value += 'This is no longer an emoji-only message';
|
||||||
textarea.value = edited_text;
|
textarea.value = edited_text;
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
|
@ -318,7 +318,7 @@ describe("Emojis", function () {
|
||||||
expect(u.hasClass('chat-msg__text--larger', message)).toBe(false);
|
expect(u.hasClass('chat-msg__text--larger', message)).toBe(false);
|
||||||
|
|
||||||
textarea.value = ':smile: Hello world!';
|
textarea.value = ':smile: Hello world!';
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
|
@ -326,7 +326,7 @@ describe("Emojis", function () {
|
||||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 4);
|
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 4);
|
||||||
|
|
||||||
textarea.value = ':smile: :smiley: :imp:';
|
textarea.value = ':smile: :smiley: :imp:';
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
|
@ -367,8 +367,8 @@ describe("Emojis", function () {
|
||||||
|
|
||||||
const textarea = view.querySelector('textarea.chat-textarea');
|
const textarea = view.querySelector('textarea.chat-textarea');
|
||||||
textarea.value = ':poop: :innocent:';
|
textarea.value = ':poop: :innocent:';
|
||||||
const bottom_panel = view.querySelector('converse-chat-bottom-panel');
|
const message_form = view.querySelector('converse-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
|
@ -385,7 +385,7 @@ describe("Emojis", function () {
|
||||||
const sent_stanza = sent_stanzas.filter(s => s.nodeName === 'message').pop();
|
const sent_stanza = sent_stanzas.filter(s => s.nodeName === 'message').pop();
|
||||||
expect(sent_stanza.querySelector('body').innerHTML).toBe('💩 😇');
|
expect(sent_stanza.querySelector('body').innerHTML).toBe('💩 😇');
|
||||||
done()
|
done()
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it("can show custom emojis",
|
it("can show custom emojis",
|
||||||
mock.initConverse(
|
mock.initConverse(
|
||||||
|
@ -419,8 +419,8 @@ describe("Emojis", function () {
|
||||||
|
|
||||||
const textarea = view.querySelector('textarea.chat-textarea');
|
const textarea = view.querySelector('textarea.chat-textarea');
|
||||||
textarea.value = 'Running tests for :converse:';
|
textarea.value = 'Running tests for :converse:';
|
||||||
const bottom_panel = view.querySelector('converse-chat-bottom-panel');
|
const message_form = view.querySelector('converse-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
|
|
|
@ -436,8 +436,8 @@ mock.sendMessage = async function (view, message) {
|
||||||
const promise = new Promise(resolve => view.model.messages.once('rendered', resolve));
|
const promise = new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||||
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
||||||
textarea.value = message;
|
textarea.value = message;
|
||||||
const bottom_panel = view.querySelector('converse-chat-bottom-panel') || view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-message-form') || view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: view.querySelector('textarea.chat-textarea'),
|
target: view.querySelector('textarea.chat-textarea'),
|
||||||
preventDefault: () => {},
|
preventDefault: () => {},
|
||||||
keyCode: 13
|
keyCode: 13
|
||||||
|
|
|
@ -64,6 +64,7 @@ const ChatBox = ModelWithContact.extend({
|
||||||
this.presence.on('change:show', item => this.onPresenceChanged(item));
|
this.presence.on('change:show', item => this.onPresenceChanged(item));
|
||||||
}
|
}
|
||||||
this.on('change:chat_state', this.sendChatState, this);
|
this.on('change:chat_state', this.sendChatState, this);
|
||||||
|
this.on('change:scrolled', () => !this.get('scrolled') && this.clearUnreadMsgCounter());
|
||||||
|
|
||||||
await this.fetchMessages();
|
await this.fetchMessages();
|
||||||
/**
|
/**
|
||||||
|
@ -198,7 +199,7 @@ const ChatBox = ModelWithContact.extend({
|
||||||
* Queue an incoming `chat` message stanza for processing.
|
* Queue an incoming `chat` message stanza for processing.
|
||||||
* @async
|
* @async
|
||||||
* @private
|
* @private
|
||||||
* @method _converse.ChatRoom#queueMessage
|
* @method _converse.ChatBox#queueMessage
|
||||||
* @param { Promise<MessageAttributes> } attrs - A promise which resolves to the message attributes
|
* @param { Promise<MessageAttributes> } attrs - A promise which resolves to the message attributes
|
||||||
*/
|
*/
|
||||||
queueMessage (attrs) {
|
queueMessage (attrs) {
|
||||||
|
@ -211,7 +212,7 @@ const ChatBox = ModelWithContact.extend({
|
||||||
/**
|
/**
|
||||||
* @async
|
* @async
|
||||||
* @private
|
* @private
|
||||||
* @method _converse.ChatRoom#onMessage
|
* @method _converse.ChatBox#onMessage
|
||||||
* @param { MessageAttributes } attrs_promse - A promise which resolves to the message attributes.
|
* @param { MessageAttributes } attrs_promse - A promise which resolves to the message attributes.
|
||||||
*/
|
*/
|
||||||
async onMessage (attrs) {
|
async onMessage (attrs) {
|
||||||
|
@ -681,7 +682,6 @@ const ChatBox = ModelWithContact.extend({
|
||||||
return _converse.connection.send(msg);
|
return _converse.connection.send(msg);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the last eligible message and then sends a XEP-0333 chat marker for it.
|
* Finds the last eligible message and then sends a XEP-0333 chat marker for it.
|
||||||
* @param { ('received'|'displayed'|'acknowledged') } [type='displayed']
|
* @param { ('received'|'displayed'|'acknowledged') } [type='displayed']
|
||||||
|
@ -866,7 +866,7 @@ const ChatBox = ModelWithContact.extend({
|
||||||
* before the collection has been fetched.
|
* before the collection has been fetched.
|
||||||
* @async
|
* @async
|
||||||
* @private
|
* @private
|
||||||
* @method _converse.ChatRoom#queueMessageCreation
|
* @method _converse.ChatBox#queueMessageCreation
|
||||||
* @param { Object } attrs
|
* @param { Object } attrs
|
||||||
*/
|
*/
|
||||||
async createMessage (attrs, options) {
|
async createMessage (attrs, options) {
|
||||||
|
@ -1029,6 +1029,7 @@ const ChatBox = ModelWithContact.extend({
|
||||||
* Given a newly received {@link _converse.Message} instance,
|
* Given a newly received {@link _converse.Message} instance,
|
||||||
* update the unread counter if necessary.
|
* update the unread counter if necessary.
|
||||||
* @private
|
* @private
|
||||||
|
* @method _converse.ChatBox#handleUnreadMessage
|
||||||
* @param {_converse.Message} message
|
* @param {_converse.Message} message
|
||||||
*/
|
*/
|
||||||
handleUnreadMessage (message) {
|
handleUnreadMessage (message) {
|
||||||
|
@ -1064,7 +1065,7 @@ const ChatBox = ModelWithContact.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
isScrolledUp () {
|
isScrolledUp () {
|
||||||
return this.get('scrolled', true);
|
return this.get('scrolled');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -97,6 +97,7 @@ const ChatRoomMixin = {
|
||||||
|
|
||||||
this.on('change:chat_state', this.sendChatState, this);
|
this.on('change:chat_state', this.sendChatState, this);
|
||||||
this.on('change:hidden', this.onHiddenChange, this);
|
this.on('change:hidden', this.onHiddenChange, this);
|
||||||
|
this.on('change:scrolled', () => !this.get('scrolled') && this.clearUnreadMsgCounter());
|
||||||
this.on('destroy', this.removeHandlers, this);
|
this.on('destroy', this.removeHandlers, this);
|
||||||
|
|
||||||
await this.restoreSession();
|
await this.restoreSession();
|
||||||
|
@ -2562,7 +2563,9 @@ const ChatRoomMixin = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/* Given a newly received message, update the unread counter if necessary.
|
/**
|
||||||
|
* Given a newly received {@link _converse.Message} instance,
|
||||||
|
* update the unread counter if necessary.
|
||||||
* @private
|
* @private
|
||||||
* @method _converse.ChatRoom#handleUnreadMessage
|
* @method _converse.ChatRoom#handleUnreadMessage
|
||||||
* @param { XMLElement } - The <messsage> stanza
|
* @param { XMLElement } - The <messsage> stanza
|
||||||
|
@ -2572,7 +2575,13 @@ const ChatRoomMixin = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (u.isNewMessage(message)) {
|
if (u.isNewMessage(message)) {
|
||||||
if (this.isHidden()) {
|
if (message.get('sender') === 'me') {
|
||||||
|
// We remove the "scrolled" flag so that the chat area
|
||||||
|
// gets scrolled down. We always want to scroll down
|
||||||
|
// when the user writes a message as opposed to when a
|
||||||
|
// message is received.
|
||||||
|
this.model.set('scrolled', false);
|
||||||
|
} else if (this.isHidden() || this.get('scrolled')) {
|
||||||
const settings = {
|
const settings = {
|
||||||
'num_unread_general': this.get('num_unread_general') + 1
|
'num_unread_general': this.get('num_unread_general') + 1
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,85 +1,42 @@
|
||||||
import tpl_chatbox_message_form from './templates/chatbox_message_form.js';
|
import './message-form.js';
|
||||||
import tpl_toolbar from './templates/toolbar.js';
|
import debounce from 'lodash-es/debounce';
|
||||||
|
import tpl_bottom_panel from './templates/bottom-panel.js';
|
||||||
import { ElementView } from '@converse/skeletor/src/element.js';
|
import { ElementView } from '@converse/skeletor/src/element.js';
|
||||||
import { __ } from 'i18n';
|
import { _converse, api } from '@converse/headless/core';
|
||||||
import { _converse, api, converse } from '@converse/headless/core';
|
import { clearMessages } from './utils.js';
|
||||||
import { html, render } from 'lit';
|
import { render } from 'lit';
|
||||||
import { clearMessages, parseMessageForCommands } from './utils.js';
|
|
||||||
|
|
||||||
import './styles/chat-bottom-panel.scss';
|
import './styles/chat-bottom-panel.scss';
|
||||||
|
|
||||||
const { u } = converse.env;
|
|
||||||
|
|
||||||
export default class ChatBottomPanel extends ElementView {
|
export default class ChatBottomPanel extends ElementView {
|
||||||
events = {
|
events = {
|
||||||
'click .send-button': 'onFormSubmitted',
|
'click .send-button': 'sendButtonClicked',
|
||||||
'click .toggle-clear': 'clearMessages'
|
'click .toggle-clear': 'clearMessages'
|
||||||
};
|
};
|
||||||
|
|
||||||
async connectedCallback () {
|
async connectedCallback () {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
|
this.debouncedRender = debounce(this.render, 100);
|
||||||
this.model = _converse.chatboxes.get(this.getAttribute('jid'));
|
this.model = _converse.chatboxes.get(this.getAttribute('jid'));
|
||||||
this.listenTo(this.model, 'change', o => this.onModelChanged(o.changed));
|
|
||||||
await this.model.initialized;
|
await this.model.initialized;
|
||||||
this.listenTo(this.model.messages, 'change:correcting', this.onMessageCorrecting);
|
this.listenTo(this.model, 'change:num_unread', this.debouncedRender)
|
||||||
|
this.listenTo(this.model, 'emoji-picker-autocomplete', this.autocompleteInPicker);
|
||||||
|
|
||||||
|
this.addEventListener('focusin', ev => this.emitFocused(ev));
|
||||||
|
this.addEventListener('focusout', ev => this.emitBlurred(ev));
|
||||||
this.render();
|
this.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
onModelChanged (changed) {
|
|
||||||
if ('composing_spoiler' in changed || 'num_unread' in changed || 'scrolled' in changed) {
|
|
||||||
this.renderMessageForm();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
render(html`<div class="message-form-container"></div>`, this);
|
render(tpl_bottom_panel({
|
||||||
this.renderMessageForm();
|
'model': this.model,
|
||||||
|
'viewUnreadMessages': ev => this.viewUnreadMessages(ev)
|
||||||
|
}), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderToolbar () {
|
sendButtonClicked (ev) {
|
||||||
if (!api.settings.get('show_toolbar')) {
|
this.querySelector('converse-message-form')?.onFormSubmitted(ev);
|
||||||
return this;
|
|
||||||
}
|
|
||||||
const options = Object.assign(
|
|
||||||
{
|
|
||||||
'model': this.model,
|
|
||||||
'chatview': _converse.chatboxviews.get(this.getAttribute('jid'))
|
|
||||||
},
|
|
||||||
this.model.toJSON(),
|
|
||||||
this.getToolbarOptions()
|
|
||||||
);
|
|
||||||
render(tpl_toolbar(options), this.querySelector('.chat-toolbar'));
|
|
||||||
/**
|
|
||||||
* Triggered once the _converse.ChatBoxView's toolbar has been rendered
|
|
||||||
* @event _converse#renderToolbar
|
|
||||||
* @type { _converse.ChatBoxView }
|
|
||||||
* @example _converse.api.listen.on('renderToolbar', this => { ... });
|
|
||||||
*/
|
|
||||||
api.trigger('renderToolbar', this);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderMessageForm () {
|
|
||||||
const form_container = this.querySelector('.message-form-container');
|
|
||||||
render(
|
|
||||||
tpl_chatbox_message_form(
|
|
||||||
Object.assign(this.model.toJSON(), {
|
|
||||||
'onDrop': ev => this.onDrop(ev),
|
|
||||||
'hint_value': this.querySelector('.spoiler-hint')?.value,
|
|
||||||
'inputChanged': ev => this.inputChanged(ev),
|
|
||||||
'message_value': this.querySelector('.chat-textarea')?.value,
|
|
||||||
'onChange': ev => this.updateCharCounter(ev.target.value),
|
|
||||||
'onKeyDown': ev => this.onKeyDown(ev),
|
|
||||||
'onKeyUp': ev => this.onKeyUp(ev),
|
|
||||||
'onPaste': ev => this.onPaste(ev),
|
|
||||||
'viewUnreadMessages': ev => this.viewUnreadMessages(ev)
|
|
||||||
})
|
|
||||||
),
|
|
||||||
form_container
|
|
||||||
);
|
|
||||||
this.addEventListener('focusin', ev => this.emitFocused(ev));
|
|
||||||
this.addEventListener('focusout', ev => this.emitBlurred(ev));
|
|
||||||
this.renderToolbar();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
viewUnreadMessages (ev) {
|
viewUnreadMessages (ev) {
|
||||||
|
@ -87,19 +44,6 @@ export default class ChatBottomPanel extends ElementView {
|
||||||
this.model.save({ 'scrolled': false });
|
this.model.save({ 'scrolled': false });
|
||||||
}
|
}
|
||||||
|
|
||||||
onMessageCorrecting (message) {
|
|
||||||
if (message.get('correcting')) {
|
|
||||||
this.insertIntoTextArea(u.prefixMentions(message), true, true);
|
|
||||||
} else {
|
|
||||||
const currently_correcting = this.model.messages.findWhere('correcting');
|
|
||||||
if (currently_correcting && currently_correcting !== message) {
|
|
||||||
this.insertIntoTextArea(u.prefixMentions(message), true, true);
|
|
||||||
} else {
|
|
||||||
this.insertIntoTextArea('', true, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
emitFocused (ev) {
|
emitFocused (ev) {
|
||||||
_converse.chatboxviews.get(this.getAttribute('jid'))?.emitFocused(ev);
|
_converse.chatboxviews.get(this.getAttribute('jid'))?.emitFocused(ev);
|
||||||
}
|
}
|
||||||
|
@ -112,18 +56,6 @@ export default class ChatBottomPanel extends ElementView {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
inputChanged (ev) { // eslint-disable-line class-methods-use-this
|
|
||||||
if (ev.target.value) {
|
|
||||||
const height = ev.target.scrollHeight + 'px';
|
|
||||||
if (ev.target.style.height != height) {
|
|
||||||
ev.target.style.height = 'auto';
|
|
||||||
ev.target.style.height = height;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ev.target.style = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onDrop (evt) {
|
onDrop (evt) {
|
||||||
if (evt.dataTransfer.files.length == 0) {
|
if (evt.dataTransfer.files.length == 0) {
|
||||||
// There are no files to be dropped, so this isn’t a file
|
// There are no files to be dropped, so this isn’t a file
|
||||||
|
@ -143,211 +75,19 @@ export default class ChatBottomPanel extends ElementView {
|
||||||
clearMessages(this.model);
|
clearMessages(this.model);
|
||||||
}
|
}
|
||||||
|
|
||||||
parseMessageForCommands (text) {
|
|
||||||
return parseMessageForCommands(this.model, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
async onFormSubmitted (ev) {
|
|
||||||
ev?.preventDefault?.();
|
|
||||||
|
|
||||||
const textarea = this.querySelector('.chat-textarea');
|
|
||||||
const message_text = textarea.value.trim();
|
|
||||||
if (
|
|
||||||
(api.settings.get('message_limit') && message_text.length > api.settings.get('message_limit')) ||
|
|
||||||
!message_text.replace(/\s/g, '').length
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!_converse.connection.authenticated) {
|
|
||||||
const err_msg = __('Sorry, the connection has been lost, and your message could not be sent');
|
|
||||||
api.alert('error', __('Error'), err_msg);
|
|
||||||
api.connection.reconnect();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let spoiler_hint,
|
|
||||||
hint_el = {};
|
|
||||||
if (this.model.get('composing_spoiler')) {
|
|
||||||
hint_el = this.querySelector('form.sendXMPPMessage input.spoiler-hint');
|
|
||||||
spoiler_hint = hint_el.value;
|
|
||||||
}
|
|
||||||
u.addClass('disabled', textarea);
|
|
||||||
textarea.setAttribute('disabled', 'disabled');
|
|
||||||
this.querySelector('converse-emoji-dropdown')?.hideMenu();
|
|
||||||
|
|
||||||
const is_command = this.parseMessageForCommands(message_text);
|
|
||||||
const message = is_command ? null : await this.model.sendMessage(message_text, spoiler_hint);
|
|
||||||
if (is_command || message) {
|
|
||||||
hint_el.value = '';
|
|
||||||
textarea.value = '';
|
|
||||||
u.removeClass('correcting', textarea);
|
|
||||||
textarea.style.height = 'auto';
|
|
||||||
this.updateCharCounter(textarea.value);
|
|
||||||
}
|
|
||||||
if (api.settings.get('view_mode') === 'overlayed') {
|
|
||||||
// XXX: Chrome flexbug workaround. The .chat-content area
|
|
||||||
// doesn't resize when the textarea is resized to its original size.
|
|
||||||
const chatview = _converse.chatboxviews.get(this.getAttribute('jid'));
|
|
||||||
const msgs_container = chatview.querySelector('.chat-content__messages');
|
|
||||||
msgs_container.parentElement.style.display = 'none';
|
|
||||||
}
|
|
||||||
textarea.removeAttribute('disabled');
|
|
||||||
u.removeClass('disabled', textarea);
|
|
||||||
|
|
||||||
if (api.settings.get('view_mode') === 'overlayed') {
|
|
||||||
// XXX: Chrome flexbug workaround.
|
|
||||||
const chatview = _converse.chatboxviews.get(this.getAttribute('jid'));
|
|
||||||
const msgs_container = chatview.querySelector('.chat-content__messages');
|
|
||||||
msgs_container.parentElement.style.display = '';
|
|
||||||
}
|
|
||||||
// Suppress events, otherwise superfluous CSN gets set
|
|
||||||
// immediately after the message, causing rate-limiting issues.
|
|
||||||
this.model.setChatState(_converse.ACTIVE, { 'silent': true });
|
|
||||||
textarea.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert a particular string value into the textarea of this chat box.
|
|
||||||
* @param {string} value - The value to be inserted.
|
|
||||||
* @param {(boolean|string)} [replace] - Whether an existing value
|
|
||||||
* should be replaced. If set to `true`, the entire textarea will
|
|
||||||
* be replaced with the new value. If set to a string, then only
|
|
||||||
* that string will be replaced *if* a position is also specified.
|
|
||||||
* @param {integer} [position] - The end index of the string to be
|
|
||||||
* replaced with the new value.
|
|
||||||
*/
|
|
||||||
insertIntoTextArea (value, replace = false, correcting = false, position) {
|
|
||||||
const textarea = this.querySelector('.chat-textarea');
|
|
||||||
if (correcting) {
|
|
||||||
u.addClass('correcting', textarea);
|
|
||||||
} else {
|
|
||||||
u.removeClass('correcting', textarea);
|
|
||||||
}
|
|
||||||
if (replace) {
|
|
||||||
if (position && typeof replace == 'string') {
|
|
||||||
textarea.value = textarea.value.replace(new RegExp(replace, 'g'), (match, offset) =>
|
|
||||||
offset == position - replace.length ? value + ' ' : match
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
textarea.value = value;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let existing = textarea.value;
|
|
||||||
if (existing && existing[existing.length - 1] !== ' ') {
|
|
||||||
existing = existing + ' ';
|
|
||||||
}
|
|
||||||
textarea.value = existing + value + ' ';
|
|
||||||
}
|
|
||||||
const ev = document.createEvent('HTMLEvents');
|
|
||||||
ev.initEvent('change', false, true);
|
|
||||||
textarea.dispatchEvent(ev);
|
|
||||||
u.placeCaretAtEnd(textarea);
|
|
||||||
}
|
|
||||||
|
|
||||||
onEscapePressed (ev) {
|
|
||||||
ev.preventDefault();
|
|
||||||
const idx = this.model.messages.findLastIndex('correcting');
|
|
||||||
const message = idx >= 0 ? this.model.messages.at(idx) : null;
|
|
||||||
if (message) {
|
|
||||||
message.save('correcting', false);
|
|
||||||
}
|
|
||||||
this.insertIntoTextArea('', true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
async autocompleteInPicker (input, value) {
|
async autocompleteInPicker (input, value) {
|
||||||
await api.emojis.initialize();
|
await api.emojis.initialize();
|
||||||
const emoji_dropdown = this.querySelector('converse-emoji-dropdown');
|
|
||||||
const emoji_picker = this.querySelector('converse-emoji-picker');
|
const emoji_picker = this.querySelector('converse-emoji-picker');
|
||||||
if (emoji_picker && emoji_dropdown) {
|
if (emoji_picker) {
|
||||||
emoji_picker.model.set({
|
emoji_picker.model.set({
|
||||||
'ac_position': input.selectionStart,
|
'ac_position': input.selectionStart,
|
||||||
'autocompleting': value,
|
'autocompleting': value,
|
||||||
'query': value
|
'query': value
|
||||||
});
|
});
|
||||||
emoji_dropdown.showMenu();
|
const emoji_dropdown = this.querySelector('converse-emoji-dropdown');
|
||||||
return true;
|
emoji_dropdown?.showMenu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onKeyDown (ev) {
|
|
||||||
if (ev.ctrlKey) {
|
|
||||||
// When ctrl is pressed, no chars are entered into the textarea.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!ev.shiftKey && !ev.altKey && !ev.metaKey) {
|
|
||||||
if (ev.keyCode === converse.keycodes.TAB) {
|
|
||||||
const value = u.getCurrentWord(ev.target, null, /(:.*?:)/g);
|
|
||||||
if (value.startsWith(':') && this.autocompleteInPicker(ev.target, value)) {
|
|
||||||
ev.preventDefault();
|
|
||||||
ev.stopPropagation();
|
|
||||||
}
|
|
||||||
} else if (ev.keyCode === converse.keycodes.FORWARD_SLASH) {
|
|
||||||
// Forward slash is used to run commands. Nothing to do here.
|
|
||||||
return;
|
|
||||||
} else if (ev.keyCode === converse.keycodes.ESCAPE) {
|
|
||||||
return this.onEscapePressed(ev, this);
|
|
||||||
} else if (ev.keyCode === converse.keycodes.ENTER) {
|
|
||||||
return this.onFormSubmitted(ev);
|
|
||||||
} else if (ev.keyCode === converse.keycodes.UP_ARROW && !ev.target.selectionEnd) {
|
|
||||||
const textarea = this.querySelector('.chat-textarea');
|
|
||||||
if (!textarea.value || u.hasClass('correcting', textarea)) {
|
|
||||||
return this.model.editEarlierMessage();
|
|
||||||
}
|
|
||||||
} else if (
|
|
||||||
ev.keyCode === converse.keycodes.DOWN_ARROW &&
|
|
||||||
ev.target.selectionEnd === ev.target.value.length &&
|
|
||||||
u.hasClass('correcting', this.querySelector('.chat-textarea'))
|
|
||||||
) {
|
|
||||||
return this.model.editLaterMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
[
|
|
||||||
converse.keycodes.SHIFT,
|
|
||||||
converse.keycodes.META,
|
|
||||||
converse.keycodes.META_RIGHT,
|
|
||||||
converse.keycodes.ESCAPE,
|
|
||||||
converse.keycodes.ALT
|
|
||||||
].includes(ev.keyCode)
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.model.get('chat_state') !== _converse.COMPOSING) {
|
|
||||||
// Set chat state to composing if keyCode is not a forward-slash
|
|
||||||
// (which would imply an internal command and not a message).
|
|
||||||
this.model.setChatState(_converse.COMPOSING);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateCharCounter (chars) {
|
|
||||||
if (api.settings.get('message_limit')) {
|
|
||||||
const message_limit = this.querySelector('.message-limit');
|
|
||||||
const counter = api.settings.get('message_limit') - chars.length;
|
|
||||||
message_limit.textContent = counter;
|
|
||||||
if (counter < 1) {
|
|
||||||
u.addClass('error', message_limit);
|
|
||||||
} else {
|
|
||||||
u.removeClass('error', message_limit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onKeyUp (ev) {
|
|
||||||
this.updateCharCounter(ev.target.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
onPaste (ev) {
|
|
||||||
ev.stopPropagation();
|
|
||||||
if (ev.clipboardData.files.length !== 0) {
|
|
||||||
ev.preventDefault();
|
|
||||||
// Workaround for quirk in at least Firefox 60.7 ESR:
|
|
||||||
// It seems that pasted files disappear from the event payload after
|
|
||||||
// the event has finished, which apparently happens during async
|
|
||||||
// processing in sendFiles(). So we copy the array here.
|
|
||||||
this.model.sendFiles(Array.from(ev.clipboardData.files));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.updateCharCounter(ev.clipboardData.getData('text/plain'));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
api.elements.define('converse-chat-bottom-panel', ChatBottomPanel);
|
api.elements.define('converse-chat-bottom-panel', ChatBottomPanel);
|
||||||
|
|
229
src/plugins/chatview/message-form.js
Normal file
229
src/plugins/chatview/message-form.js
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
import tpl_message_form from './templates/message-form.js';
|
||||||
|
import { ElementView } from '@converse/skeletor/src/element.js';
|
||||||
|
import { __ } from 'i18n';
|
||||||
|
import { _converse, api, converse } from "@converse/headless/core";
|
||||||
|
import { parseMessageForCommands } from './utils.js';
|
||||||
|
|
||||||
|
const { u } = converse.env;
|
||||||
|
|
||||||
|
|
||||||
|
export default class MessageForm extends ElementView {
|
||||||
|
|
||||||
|
async connectedCallback () {
|
||||||
|
super.connectedCallback();
|
||||||
|
this.model = _converse.chatboxes.get(this.getAttribute('jid'));
|
||||||
|
await this.model.initialized;
|
||||||
|
this.listenTo(this.model.messages, 'change:correcting', this.onMessageCorrecting);
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
toHTML () {
|
||||||
|
return tpl_message_form(
|
||||||
|
Object.assign(this.model.toJSON(), {
|
||||||
|
'onDrop': ev => this.onDrop(ev),
|
||||||
|
'hint_value': this.querySelector('.spoiler-hint')?.value,
|
||||||
|
'message_value': this.querySelector('.chat-textarea')?.value,
|
||||||
|
'onChange': ev => this.model.set({'draft': ev.target.value}),
|
||||||
|
'onKeyDown': ev => this.onKeyDown(ev),
|
||||||
|
'onKeyUp': ev => this.onKeyUp(ev),
|
||||||
|
'onPaste': ev => this.onPaste(ev),
|
||||||
|
'viewUnreadMessages': ev => this.viewUnreadMessages(ev)
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a particular string value into the textarea of this chat box.
|
||||||
|
* @param {string} value - The value to be inserted.
|
||||||
|
* @param {(boolean|string)} [replace] - Whether an existing value
|
||||||
|
* should be replaced. If set to `true`, the entire textarea will
|
||||||
|
* be replaced with the new value. If set to a string, then only
|
||||||
|
* that string will be replaced *if* a position is also specified.
|
||||||
|
* @param {integer} [position] - The end index of the string to be
|
||||||
|
* replaced with the new value.
|
||||||
|
*/
|
||||||
|
insertIntoTextArea (value, replace = false, correcting = false, position) {
|
||||||
|
const textarea = this.querySelector('.chat-textarea');
|
||||||
|
if (correcting) {
|
||||||
|
u.addClass('correcting', textarea);
|
||||||
|
} else {
|
||||||
|
u.removeClass('correcting', textarea);
|
||||||
|
}
|
||||||
|
if (replace) {
|
||||||
|
if (position && typeof replace == 'string') {
|
||||||
|
textarea.value = textarea.value.replace(new RegExp(replace, 'g'), (match, offset) =>
|
||||||
|
offset == position - replace.length ? value + ' ' : match
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
textarea.value = value;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let existing = textarea.value;
|
||||||
|
if (existing && existing[existing.length - 1] !== ' ') {
|
||||||
|
existing = existing + ' ';
|
||||||
|
}
|
||||||
|
textarea.value = existing + value + ' ';
|
||||||
|
}
|
||||||
|
const ev = document.createEvent('HTMLEvents');
|
||||||
|
ev.initEvent('change', false, true);
|
||||||
|
textarea.dispatchEvent(ev);
|
||||||
|
u.placeCaretAtEnd(textarea);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMessageCorrecting (message) {
|
||||||
|
if (message.get('correcting')) {
|
||||||
|
this.insertIntoTextArea(u.prefixMentions(message), true, true);
|
||||||
|
} else {
|
||||||
|
const currently_correcting = this.model.messages.findWhere('correcting');
|
||||||
|
if (currently_correcting && currently_correcting !== message) {
|
||||||
|
this.insertIntoTextArea(u.prefixMentions(message), true, true);
|
||||||
|
} else {
|
||||||
|
this.insertIntoTextArea('', true, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onEscapePressed (ev) {
|
||||||
|
ev.preventDefault();
|
||||||
|
const idx = this.model.messages.findLastIndex('correcting');
|
||||||
|
const message = idx >= 0 ? this.model.messages.at(idx) : null;
|
||||||
|
if (message) {
|
||||||
|
message.save('correcting', false);
|
||||||
|
}
|
||||||
|
this.insertIntoTextArea('', true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
onPaste (ev) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
if (ev.clipboardData.files.length !== 0) {
|
||||||
|
ev.preventDefault();
|
||||||
|
// Workaround for quirk in at least Firefox 60.7 ESR:
|
||||||
|
// It seems that pasted files disappear from the event payload after
|
||||||
|
// the event has finished, which apparently happens during async
|
||||||
|
// processing in sendFiles(). So we copy the array here.
|
||||||
|
this.model.sendFiles(Array.from(ev.clipboardData.files));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.model.set({'draft': ev.clipboardData.getData('text/plain')});
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyUp (ev) {
|
||||||
|
this.model.set({'draft': ev.target.value});
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyDown (ev) {
|
||||||
|
if (ev.ctrlKey) {
|
||||||
|
// When ctrl is pressed, no chars are entered into the textarea.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!ev.shiftKey && !ev.altKey && !ev.metaKey) {
|
||||||
|
if (ev.keyCode === converse.keycodes.TAB) {
|
||||||
|
const value = u.getCurrentWord(ev.target, null, /(:.*?:)/g);
|
||||||
|
if (value.startsWith(':')) {
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.model.trigger('emoji-picker-autocomplete', ev.target, value);
|
||||||
|
}
|
||||||
|
} else if (ev.keyCode === converse.keycodes.FORWARD_SLASH) {
|
||||||
|
// Forward slash is used to run commands. Nothing to do here.
|
||||||
|
return;
|
||||||
|
} else if (ev.keyCode === converse.keycodes.ESCAPE) {
|
||||||
|
return this.onEscapePressed(ev, this);
|
||||||
|
} else if (ev.keyCode === converse.keycodes.ENTER) {
|
||||||
|
return this.onFormSubmitted(ev);
|
||||||
|
} else if (ev.keyCode === converse.keycodes.UP_ARROW && !ev.target.selectionEnd) {
|
||||||
|
const textarea = this.querySelector('.chat-textarea');
|
||||||
|
if (!textarea.value || u.hasClass('correcting', textarea)) {
|
||||||
|
return this.model.editEarlierMessage();
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
ev.keyCode === converse.keycodes.DOWN_ARROW &&
|
||||||
|
ev.target.selectionEnd === ev.target.value.length &&
|
||||||
|
u.hasClass('correcting', this.querySelector('.chat-textarea'))
|
||||||
|
) {
|
||||||
|
return this.model.editLaterMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
[
|
||||||
|
converse.keycodes.SHIFT,
|
||||||
|
converse.keycodes.META,
|
||||||
|
converse.keycodes.META_RIGHT,
|
||||||
|
converse.keycodes.ESCAPE,
|
||||||
|
converse.keycodes.ALT
|
||||||
|
].includes(ev.keyCode)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.model.get('chat_state') !== _converse.COMPOSING) {
|
||||||
|
// Set chat state to composing if keyCode is not a forward-slash
|
||||||
|
// (which would imply an internal command and not a message).
|
||||||
|
this.model.setChatState(_converse.COMPOSING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parseMessageForCommands (text) {
|
||||||
|
// Wrap util so that we can override in the MUC message-form component
|
||||||
|
return parseMessageForCommands(this.model, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
async onFormSubmitted (ev) {
|
||||||
|
ev?.preventDefault?.();
|
||||||
|
|
||||||
|
const textarea = this.querySelector('.chat-textarea');
|
||||||
|
const message_text = textarea.value.trim();
|
||||||
|
if (
|
||||||
|
(api.settings.get('message_limit') && message_text.length > api.settings.get('message_limit')) ||
|
||||||
|
!message_text.replace(/\s/g, '').length
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!_converse.connection.authenticated) {
|
||||||
|
const err_msg = __('Sorry, the connection has been lost, and your message could not be sent');
|
||||||
|
api.alert('error', __('Error'), err_msg);
|
||||||
|
api.connection.reconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let spoiler_hint,
|
||||||
|
hint_el = {};
|
||||||
|
if (this.model.get('composing_spoiler')) {
|
||||||
|
hint_el = this.querySelector('form.sendXMPPMessage input.spoiler-hint');
|
||||||
|
spoiler_hint = hint_el.value;
|
||||||
|
}
|
||||||
|
u.addClass('disabled', textarea);
|
||||||
|
textarea.setAttribute('disabled', 'disabled');
|
||||||
|
this.querySelector('converse-emoji-dropdown')?.hideMenu();
|
||||||
|
|
||||||
|
const is_command = this.parseMessageForCommands(message_text);
|
||||||
|
const message = is_command ? null : await this.model.sendMessage(message_text, spoiler_hint);
|
||||||
|
if (is_command || message) {
|
||||||
|
hint_el.value = '';
|
||||||
|
textarea.value = '';
|
||||||
|
u.removeClass('correcting', textarea);
|
||||||
|
textarea.style.height = 'auto';
|
||||||
|
this.model.set({'draft': ''});
|
||||||
|
}
|
||||||
|
if (api.settings.get('view_mode') === 'overlayed') {
|
||||||
|
// XXX: Chrome flexbug workaround. The .chat-content area
|
||||||
|
// doesn't resize when the textarea is resized to its original size.
|
||||||
|
const chatview = _converse.chatboxviews.get(this.getAttribute('jid'));
|
||||||
|
const msgs_container = chatview.querySelector('.chat-content__messages');
|
||||||
|
msgs_container.parentElement.style.display = 'none';
|
||||||
|
}
|
||||||
|
textarea.removeAttribute('disabled');
|
||||||
|
u.removeClass('disabled', textarea);
|
||||||
|
|
||||||
|
if (api.settings.get('view_mode') === 'overlayed') {
|
||||||
|
// XXX: Chrome flexbug workaround.
|
||||||
|
const chatview = _converse.chatboxviews.get(this.getAttribute('jid'));
|
||||||
|
const msgs_container = chatview.querySelector('.chat-content__messages');
|
||||||
|
msgs_container.parentElement.style.display = '';
|
||||||
|
}
|
||||||
|
// Suppress events, otherwise superfluous CSN gets set
|
||||||
|
// immediately after the message, causing rate-limiting issues.
|
||||||
|
this.model.setChatState(_converse.ACTIVE, { 'silent': true });
|
||||||
|
textarea.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
api.elements.define('converse-message-form', MessageForm);
|
|
@ -1,4 +1,30 @@
|
||||||
|
import { __ } from 'i18n';
|
||||||
|
import { api } from '@converse/headless/core';
|
||||||
|
import { html } from 'lit';
|
||||||
|
|
||||||
<div class="bottom-panel">
|
|
||||||
<div class="message-form-container"></div>
|
export default (o) => {
|
||||||
</div>
|
const unread_msgs = __('You have unread messages');
|
||||||
|
const message_limit = api.settings.get('message_limit');
|
||||||
|
const show_call_button = api.settings.get('visible_toolbar_buttons').call;
|
||||||
|
const show_emoji_button = api.settings.get('visible_toolbar_buttons').emoji;
|
||||||
|
const show_send_button = api.settings.get('show_send_button');
|
||||||
|
const show_spoiler_button = api.settings.get('visible_toolbar_buttons').spoiler;
|
||||||
|
const show_toolbar = api.settings.get('show_toolbar');
|
||||||
|
return html`
|
||||||
|
${ o.model.get('scrolled') && o.model.get('num_unread') ?
|
||||||
|
html`<div class="new-msgs-indicator" @click=${ev => o.viewUnreadMessages(ev)}>▼ ${ unread_msgs } ▼</div>` : '' }
|
||||||
|
${api.settings.get('show_toolbar') ? html`
|
||||||
|
<converse-chat-toolbar
|
||||||
|
class="chat-toolbar no-text-select"
|
||||||
|
.model=${o.model}
|
||||||
|
?composing_spoiler="${o.model.get('composing_spoiler')}"
|
||||||
|
?show_call_button="${show_call_button}"
|
||||||
|
?show_emoji_button="${show_emoji_button}"
|
||||||
|
?show_send_button="${show_send_button}"
|
||||||
|
?show_spoiler_button="${show_spoiler_button}"
|
||||||
|
?show_toolbar="${show_toolbar}"
|
||||||
|
message_limit="${message_limit}"></converse-chat-toolbar>` : '' }
|
||||||
|
<converse-message-form jid="${o.model.get('jid')}"></converse-message-form>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
29
src/plugins/chatview/templates/message-form.js
Normal file
29
src/plugins/chatview/templates/message-form.js
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import { __ } from 'i18n';
|
||||||
|
import { api } from "@converse/headless/core";
|
||||||
|
import { html } from "lit";
|
||||||
|
import { resetElementHeight } from '../utils.js';
|
||||||
|
|
||||||
|
|
||||||
|
export default (o) => {
|
||||||
|
const label_message = o.composing_spoiler ? __('Hidden message') : __('Message');
|
||||||
|
const label_spoiler_hint = __('Optional hint');
|
||||||
|
const show_send_button = api.settings.get('show_send_button');
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<form class="sendXMPPMessage">
|
||||||
|
<input type="text" placeholder="${label_spoiler_hint || ''}" value="${o.hint_value || ''}" class="${o.composing_spoiler ? '' : 'hidden'} spoiler-hint"/>
|
||||||
|
<textarea
|
||||||
|
autofocus
|
||||||
|
type="text"
|
||||||
|
@drop=${o.onDrop}
|
||||||
|
@input=${resetElementHeight}
|
||||||
|
@keydown=${o.onKeyDown}
|
||||||
|
@keyup=${o.onKeyUp}
|
||||||
|
@paste=${o.onPaste}
|
||||||
|
@change=${o.onChange}
|
||||||
|
class="chat-textarea
|
||||||
|
${ show_send_button ? 'chat-textarea-send-button' : '' }
|
||||||
|
${ o.composing_spoiler ? 'spoiler' : '' }"
|
||||||
|
placeholder="${label_message}">${ o.message_value || '' }</textarea>
|
||||||
|
</form>`;
|
||||||
|
}
|
|
@ -1,28 +0,0 @@
|
||||||
import 'shared/chat/toolbar.js';
|
|
||||||
import { api } from '@converse/headless/core.js';
|
|
||||||
import { html } from "lit";
|
|
||||||
|
|
||||||
export default (o) => {
|
|
||||||
const message_limit = api.settings.get('message_limit');
|
|
||||||
const show_call_button = api.settings.get('visible_toolbar_buttons').call;
|
|
||||||
const show_emoji_button = api.settings.get('visible_toolbar_buttons').emoji;
|
|
||||||
const show_send_button = api.settings.get('show_send_button');
|
|
||||||
const show_spoiler_button = api.settings.get('visible_toolbar_buttons').spoiler;
|
|
||||||
const show_toolbar = api.settings.get('show_toolbar');
|
|
||||||
return html`
|
|
||||||
<converse-chat-toolbar
|
|
||||||
.chatview=${o.chatview}
|
|
||||||
.model=${o.model}
|
|
||||||
?composing_spoiler="${o.composing_spoiler}"
|
|
||||||
?hidden_occupants="${o.hidden_occupants}"
|
|
||||||
?is_groupchat="${o.is_groupchat}"
|
|
||||||
?show_call_button="${show_call_button}"
|
|
||||||
?show_emoji_button="${show_emoji_button}"
|
|
||||||
?show_occupants_toggle="${o.show_occupants_toggle}"
|
|
||||||
?show_send_button="${show_send_button}"
|
|
||||||
?show_spoiler_button="${show_spoiler_button}"
|
|
||||||
?show_toolbar="${show_toolbar}"
|
|
||||||
message_limit="${message_limit}"
|
|
||||||
></converse-chat-toolbar>
|
|
||||||
`;
|
|
||||||
}
|
|
|
@ -59,8 +59,8 @@ describe("Chatboxes", function () {
|
||||||
|
|
||||||
const textarea = view.querySelector('textarea.chat-textarea');
|
const textarea = view.querySelector('textarea.chat-textarea');
|
||||||
textarea.value = '/clear';
|
textarea.value = '/clear';
|
||||||
const bottom_panel = view.querySelector('converse-chat-bottom-panel');
|
const message_form = view.querySelector('converse-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
|
@ -264,14 +264,14 @@ describe("Chatboxes", function () {
|
||||||
const toolbar = view.querySelector('.chat-toolbar');
|
const toolbar = view.querySelector('.chat-toolbar');
|
||||||
const counter = toolbar.querySelector('.message-limit');
|
const counter = toolbar.querySelector('.message-limit');
|
||||||
expect(counter.textContent).toBe('200');
|
expect(counter.textContent).toBe('200');
|
||||||
view.getBottomPanel().insertIntoTextArea('hello world');
|
view.getMessageForm().insertIntoTextArea('hello world');
|
||||||
expect(counter.textContent).toBe('188');
|
await u.waitUntil(() => counter.textContent === '188');
|
||||||
|
|
||||||
toolbar.querySelector('.toggle-emojis').click();
|
toolbar.querySelector('.toggle-emojis').click();
|
||||||
const picker = await u.waitUntil(() => view.querySelector('.emoji-picker__lists'));
|
const picker = await u.waitUntil(() => view.querySelector('.emoji-picker__lists'));
|
||||||
const item = await u.waitUntil(() => picker.querySelector('.emoji-picker li.insert-emoji a'));
|
const item = await u.waitUntil(() => picker.querySelector('.emoji-picker li.insert-emoji a'));
|
||||||
item.click()
|
item.click()
|
||||||
expect(counter.textContent).toBe('179');
|
await u.waitUntil(() => counter.textContent === '179');
|
||||||
|
|
||||||
const textarea = view.querySelector('.chat-textarea');
|
const textarea = view.querySelector('.chat-textarea');
|
||||||
const ev = {
|
const ev = {
|
||||||
|
@ -279,15 +279,15 @@ describe("Chatboxes", function () {
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
};
|
};
|
||||||
const bottom_panel = view.querySelector('converse-chat-bottom-panel');
|
const message_form = view.querySelector('converse-message-form');
|
||||||
bottom_panel.onKeyDown(ev);
|
message_form.onKeyDown(ev);
|
||||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
|
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
|
||||||
bottom_panel.onKeyUp(ev);
|
message_form.onKeyUp(ev);
|
||||||
expect(counter.textContent).toBe('200');
|
expect(counter.textContent).toBe('200');
|
||||||
|
|
||||||
textarea.value = 'hello world';
|
textarea.value = 'hello world';
|
||||||
bottom_panel.onKeyUp(ev);
|
message_form.onKeyUp(ev);
|
||||||
expect(counter.textContent).toBe('189');
|
await u.waitUntil(() => counter.textContent === '189');
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -430,8 +430,8 @@ describe("Chatboxes", function () {
|
||||||
spyOn(_converse.connection, 'send');
|
spyOn(_converse.connection, 'send');
|
||||||
spyOn(_converse.api, "trigger").and.callThrough();
|
spyOn(_converse.api, "trigger").and.callThrough();
|
||||||
|
|
||||||
const bottom_panel = view.querySelector('converse-chat-bottom-panel');
|
const message_form = view.querySelector('converse-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: view.querySelector('textarea.chat-textarea'),
|
target: view.querySelector('textarea.chat-textarea'),
|
||||||
keyCode: 1
|
keyCode: 1
|
||||||
});
|
});
|
||||||
|
@ -446,7 +446,7 @@ describe("Chatboxes", function () {
|
||||||
expect(stanza.childNodes[2].tagName).toBe('no-permanent-store');
|
expect(stanza.childNodes[2].tagName).toBe('no-permanent-store');
|
||||||
|
|
||||||
// The notification is not sent again
|
// The notification is not sent again
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: view.querySelector('textarea.chat-textarea'),
|
target: view.querySelector('textarea.chat-textarea'),
|
||||||
keyCode: 1
|
keyCode: 1
|
||||||
});
|
});
|
||||||
|
@ -470,8 +470,8 @@ describe("Chatboxes", function () {
|
||||||
expect(view.model.get('chat_state')).toBe('active');
|
expect(view.model.get('chat_state')).toBe('active');
|
||||||
spyOn(_converse.connection, 'send');
|
spyOn(_converse.connection, 'send');
|
||||||
spyOn(_converse.api, "trigger").and.callThrough();
|
spyOn(_converse.api, "trigger").and.callThrough();
|
||||||
const bottom_panel = view.querySelector('converse-chat-bottom-panel');
|
const message_form = view.querySelector('converse-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: view.querySelector('textarea.chat-textarea'),
|
target: view.querySelector('textarea.chat-textarea'),
|
||||||
keyCode: 1
|
keyCode: 1
|
||||||
});
|
});
|
||||||
|
@ -579,8 +579,8 @@ describe("Chatboxes", function () {
|
||||||
const view = _converse.chatboxviews.get(contact_jid);
|
const view = _converse.chatboxviews.get(contact_jid);
|
||||||
spyOn(view.model, 'setChatState').and.callThrough();
|
spyOn(view.model, 'setChatState').and.callThrough();
|
||||||
expect(view.model.get('chat_state')).toBe('active');
|
expect(view.model.get('chat_state')).toBe('active');
|
||||||
const bottom_panel = view.querySelector('converse-chat-bottom-panel');
|
const message_form = view.querySelector('converse-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: view.querySelector('textarea.chat-textarea'),
|
target: view.querySelector('textarea.chat-textarea'),
|
||||||
keyCode: 1
|
keyCode: 1
|
||||||
});
|
});
|
||||||
|
@ -612,14 +612,14 @@ describe("Chatboxes", function () {
|
||||||
// Test #359. A paused notification should not be sent
|
// Test #359. A paused notification should not be sent
|
||||||
// out if the user simply types longer than the
|
// out if the user simply types longer than the
|
||||||
// timeout.
|
// timeout.
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: view.querySelector('textarea.chat-textarea'),
|
target: view.querySelector('textarea.chat-textarea'),
|
||||||
keyCode: 1
|
keyCode: 1
|
||||||
});
|
});
|
||||||
expect(view.model.setChatState).toHaveBeenCalled();
|
expect(view.model.setChatState).toHaveBeenCalled();
|
||||||
expect(view.model.get('chat_state')).toBe('composing');
|
expect(view.model.get('chat_state')).toBe('composing');
|
||||||
|
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: view.querySelector('textarea.chat-textarea'),
|
target: view.querySelector('textarea.chat-textarea'),
|
||||||
keyCode: 1
|
keyCode: 1
|
||||||
});
|
});
|
||||||
|
@ -718,8 +718,8 @@ describe("Chatboxes", function () {
|
||||||
`</message>`);
|
`</message>`);
|
||||||
|
|
||||||
|
|
||||||
const bottom_panel = view.querySelector('converse-chat-bottom-panel');
|
const message_form = view.querySelector('converse-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: view.querySelector('textarea.chat-textarea'),
|
target: view.querySelector('textarea.chat-textarea'),
|
||||||
keyCode: 1
|
keyCode: 1
|
||||||
});
|
});
|
||||||
|
@ -937,10 +937,10 @@ describe("Chatboxes", function () {
|
||||||
await u.waitUntil(() => view.querySelector('.chat-msg'));
|
await u.waitUntil(() => view.querySelector('.chat-msg'));
|
||||||
|
|
||||||
message = '/clear';
|
message = '/clear';
|
||||||
const bottom_panel = view.querySelector('converse-chat-bottom-panel');
|
const message_form = view.querySelector('converse-message-form');
|
||||||
spyOn(window, 'confirm').and.callFake(() => true);
|
spyOn(window, 'confirm').and.callFake(() => true);
|
||||||
view.querySelector('.chat-textarea').value = message;
|
view.querySelector('.chat-textarea').value = message;
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: view.querySelector('textarea.chat-textarea'),
|
target: view.querySelector('textarea.chat-textarea'),
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13
|
keyCode: 13
|
||||||
|
@ -1191,7 +1191,7 @@ describe("Chatboxes", function () {
|
||||||
const view = _converse.chatboxviews.get(sender_jid);
|
const view = _converse.chatboxviews.get(sender_jid);
|
||||||
await u.waitUntil(() => view.model.messages.length);
|
await u.waitUntil(() => view.model.messages.length);
|
||||||
expect(select_msgs_indicator().textContent).toBe('1');
|
expect(select_msgs_indicator().textContent).toBe('1');
|
||||||
const chat_new_msgs_indicator = view.querySelector('.new-msgs-indicator');
|
const chat_new_msgs_indicator = await u.waitUntil(() => view.querySelector('.new-msgs-indicator'));
|
||||||
chat_new_msgs_indicator.click();
|
chat_new_msgs_indicator.click();
|
||||||
await u.waitUntil(() => select_msgs_indicator() === undefined);
|
await u.waitUntil(() => select_msgs_indicator() === undefined);
|
||||||
done();
|
done();
|
||||||
|
|
|
@ -14,15 +14,15 @@ describe("A Chat Message", function () {
|
||||||
const view = _converse.api.chatviews.get(contact_jid);
|
const view = _converse.api.chatviews.get(contact_jid);
|
||||||
const textarea = view.querySelector('textarea.chat-textarea');
|
const textarea = view.querySelector('textarea.chat-textarea');
|
||||||
expect(textarea.value).toBe('');
|
expect(textarea.value).toBe('');
|
||||||
const bottom_panel = view.querySelector('converse-chat-bottom-panel');
|
const message_form = view.querySelector('converse-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
keyCode: 38 // Up arrow
|
keyCode: 38 // Up arrow
|
||||||
});
|
});
|
||||||
expect(textarea.value).toBe('');
|
expect(textarea.value).toBe('');
|
||||||
|
|
||||||
textarea.value = 'But soft, what light through yonder airlock breaks?';
|
textarea.value = 'But soft, what light through yonder airlock breaks?';
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
|
@ -34,7 +34,7 @@ describe("A Chat Message", function () {
|
||||||
|
|
||||||
const first_msg = view.model.messages.findWhere({'message': 'But soft, what light through yonder airlock breaks?'});
|
const first_msg = view.model.messages.findWhere({'message': 'But soft, what light through yonder airlock breaks?'});
|
||||||
expect(textarea.value).toBe('');
|
expect(textarea.value).toBe('');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
keyCode: 38 // Up arrow
|
keyCode: 38 // Up arrow
|
||||||
});
|
});
|
||||||
|
@ -46,7 +46,7 @@ describe("A Chat Message", function () {
|
||||||
spyOn(_converse.connection, 'send');
|
spyOn(_converse.connection, 'send');
|
||||||
let new_text = 'But soft, what light through yonder window breaks?';
|
let new_text = 'But soft, what light through yonder window breaks?';
|
||||||
textarea.value = new_text;
|
textarea.value = new_text;
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
|
@ -80,7 +80,7 @@ describe("A Chat Message", function () {
|
||||||
|
|
||||||
// Test that pressing the down arrow cancels message correction
|
// Test that pressing the down arrow cancels message correction
|
||||||
await u.waitUntil(() => textarea.value === '')
|
await u.waitUntil(() => textarea.value === '')
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
keyCode: 38 // Up arrow
|
keyCode: 38 // Up arrow
|
||||||
});
|
});
|
||||||
|
@ -89,7 +89,7 @@ describe("A Chat Message", function () {
|
||||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||||
await u.waitUntil(() => u.hasClass('correcting', view.querySelector('.chat-msg')), 500);
|
await u.waitUntil(() => u.hasClass('correcting', view.querySelector('.chat-msg')), 500);
|
||||||
expect(textarea.value).toBe('But soft, what light through yonder window breaks?');
|
expect(textarea.value).toBe('But soft, what light through yonder window breaks?');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
keyCode: 40 // Down arrow
|
keyCode: 40 // Down arrow
|
||||||
});
|
});
|
||||||
|
@ -100,7 +100,7 @@ describe("A Chat Message", function () {
|
||||||
|
|
||||||
new_text = 'It is the east, and Juliet is the one.';
|
new_text = 'It is the east, and Juliet is the one.';
|
||||||
textarea.value = new_text;
|
textarea.value = new_text;
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
|
@ -110,14 +110,14 @@ describe("A Chat Message", function () {
|
||||||
expect(view.querySelectorAll('.chat-msg').length).toBe(2);
|
expect(view.querySelectorAll('.chat-msg').length).toBe(2);
|
||||||
|
|
||||||
textarea.value = 'Arise, fair sun, and kill the envious moon';
|
textarea.value = 'Arise, fair sun, and kill the envious moon';
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
});
|
});
|
||||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 3);
|
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 3);
|
||||||
|
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
keyCode: 38 // Up arrow
|
keyCode: 38 // Up arrow
|
||||||
});
|
});
|
||||||
|
@ -129,7 +129,7 @@ describe("A Chat Message", function () {
|
||||||
|
|
||||||
textarea.selectionEnd = 0; // Happens by pressing up,
|
textarea.selectionEnd = 0; // Happens by pressing up,
|
||||||
// but for some reason not in tests, so we set it manually.
|
// but for some reason not in tests, so we set it manually.
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
keyCode: 38 // Up arrow
|
keyCode: 38 // Up arrow
|
||||||
});
|
});
|
||||||
|
@ -140,7 +140,7 @@ describe("A Chat Message", function () {
|
||||||
await u.waitUntil(() => u.hasClass('correcting', sizzle('.chat-msg', view)[1]), 500);
|
await u.waitUntil(() => u.hasClass('correcting', sizzle('.chat-msg', view)[1]), 500);
|
||||||
|
|
||||||
textarea.value = 'It is the east, and Juliet is the sun.';
|
textarea.value = 'It is the east, and Juliet is the sun.';
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
|
@ -176,8 +176,8 @@ describe("A Chat Message", function () {
|
||||||
const textarea = view.querySelector('textarea.chat-textarea');
|
const textarea = view.querySelector('textarea.chat-textarea');
|
||||||
|
|
||||||
textarea.value = 'But soft, what light through yonder airlock breaks?';
|
textarea.value = 'But soft, what light through yonder airlock breaks?';
|
||||||
const bottom_panel = view.querySelector('converse-chat-bottom-panel');
|
const message_form = view.querySelector('converse-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
|
@ -204,7 +204,7 @@ describe("A Chat Message", function () {
|
||||||
|
|
||||||
spyOn(_converse.connection, 'send');
|
spyOn(_converse.connection, 'send');
|
||||||
textarea.value = 'But soft, what light through yonder window breaks?';
|
textarea.value = 'But soft, what light through yonder window breaks?';
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
|
|
|
@ -125,8 +125,8 @@ describe("A XEP-0333 Chat Marker", function () {
|
||||||
const view = _converse.api.chatviews.get(muc_jid);
|
const view = _converse.api.chatviews.get(muc_jid);
|
||||||
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
||||||
textarea.value = 'But soft, what light through yonder airlock breaks?';
|
textarea.value = 'But soft, what light through yonder airlock breaks?';
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
|
|
|
@ -1213,14 +1213,13 @@ describe("A Chat Message", function () {
|
||||||
}
|
}
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
|
|
||||||
const indicator_el = view.querySelector('.new-msgs-indicator');
|
const indicator_el = await u.waitUntil(() => view.querySelector('.new-msgs-indicator'));
|
||||||
expect(u.isVisible(indicator_el)).toBeTruthy();
|
|
||||||
|
|
||||||
expect(view.model.get('scrolled')).toBe(true);
|
expect(view.model.get('scrolled')).toBe(true);
|
||||||
expect(view.querySelector('.chat-content').scrollTop).toBe(0);
|
expect(view.querySelector('.chat-content').scrollTop).toBe(0);
|
||||||
indicator_el.click();
|
indicator_el.click();
|
||||||
expect(u.isVisible(indicator_el)).toBeFalsy();
|
await u.waitUntil(() => !view.querySelector('.new-msgs-indicator'));
|
||||||
expect(view.model.get('scrolled')).toBe(false);
|
await u.waitUntil(() => !view.model.get('scrolled'));
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
@ -110,8 +110,8 @@ describe("A delivery receipt", function () {
|
||||||
const view = _converse.chatboxviews.get(contact_jid);
|
const view = _converse.chatboxviews.get(contact_jid);
|
||||||
const textarea = view.querySelector('textarea.chat-textarea');
|
const textarea = view.querySelector('textarea.chat-textarea');
|
||||||
textarea.value = 'But soft, what light through yonder airlock breaks?';
|
textarea.value = 'But soft, what light through yonder airlock breaks?';
|
||||||
const bottom_panel = view.querySelector('converse-chat-bottom-panel');
|
const message_form = view.querySelector('converse-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
|
@ -132,7 +132,7 @@ describe("A delivery receipt", function () {
|
||||||
// Also handle receipts with type 'chat'. See #1353
|
// Also handle receipts with type 'chat'. See #1353
|
||||||
spyOn(_converse, 'handleMessageStanza').and.callThrough();
|
spyOn(_converse, 'handleMessageStanza').and.callThrough();
|
||||||
textarea.value = 'Another message';
|
textarea.value = 'Another message';
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
|
|
|
@ -112,8 +112,8 @@ describe("A spoiler message", function () {
|
||||||
|
|
||||||
const textarea = view.querySelector('.chat-textarea');
|
const textarea = view.querySelector('.chat-textarea');
|
||||||
textarea.value = 'This is the spoiler';
|
textarea.value = 'This is the spoiler';
|
||||||
const bottom_panel = view.querySelector('converse-chat-bottom-panel');
|
const message_form = view.querySelector('converse-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13
|
keyCode: 13
|
||||||
|
@ -193,8 +193,8 @@ describe("A spoiler message", function () {
|
||||||
const hint_input = view.querySelector('.spoiler-hint');
|
const hint_input = view.querySelector('.spoiler-hint');
|
||||||
hint_input.value = 'This is the hint';
|
hint_input.value = 'This is the hint';
|
||||||
|
|
||||||
const bottom_panel = view.querySelector('converse-chat-bottom-panel');
|
const message_form = view.querySelector('converse-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13
|
keyCode: 13
|
||||||
|
|
|
@ -48,3 +48,15 @@ export function parseMessageForCommands (chat, text) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function resetElementHeight (ev) {
|
||||||
|
if (ev.target.value) {
|
||||||
|
const height = ev.target.scrollHeight + 'px';
|
||||||
|
if (ev.target.style.height != height) {
|
||||||
|
ev.target.style.height = 'auto';
|
||||||
|
ev.target.style.height = height;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ev.target.style = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -141,7 +141,6 @@ export default class ChatView extends BaseChatView {
|
||||||
}
|
}
|
||||||
|
|
||||||
afterShown () {
|
afterShown () {
|
||||||
this.model.clearUnreadMsgCounter();
|
|
||||||
this.model.setChatState(_converse.ACTIVE);
|
this.model.setChatState(_converse.ACTIVE);
|
||||||
this.scrollDown();
|
this.scrollDown();
|
||||||
this.maybeFocus();
|
this.maybeFocus();
|
||||||
|
|
|
@ -8,7 +8,7 @@ export default (o) => {
|
||||||
return html`
|
return html`
|
||||||
<div class="chatbox-title ${ o.status ? '' : "chatbox-title--no-desc"}">
|
<div class="chatbox-title ${ o.status ? '' : "chatbox-title--no-desc"}">
|
||||||
<div class="chatbox-title--row">
|
<div class="chatbox-title--row">
|
||||||
${ (!_converse.api.settings.get("singleton")) ? html`<div class="chatbox-navback"><i class="fa fa-arrow-left"></i></div>` : '' }
|
${ (!_converse.api.settings.get("singleton")) ? html`<converse-controlbox-navback jid="${o.jid}"></converse-controlbox-navback>` : '' }
|
||||||
<div class="chatbox-title__text" title="${o.jid}">${ o.display_name }</div>
|
<div class="chatbox-title__text" title="${o.jid}">${ o.display_name }</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="chatbox-title__buttons row no-gutters">
|
<div class="chatbox-title__buttons row no-gutters">
|
||||||
|
|
|
@ -4,7 +4,6 @@ import debounce from 'lodash-es/debounce';
|
||||||
import tpl_muc_bottom_panel from './templates/muc-bottom-panel.js';
|
import tpl_muc_bottom_panel from './templates/muc-bottom-panel.js';
|
||||||
import { __ } from 'i18n';
|
import { __ } from 'i18n';
|
||||||
import { _converse, api, converse } from "@converse/headless/core";
|
import { _converse, api, converse } from "@converse/headless/core";
|
||||||
import { getAutoCompleteListItem, parseMessageForMUCCommands } from './utils.js';
|
|
||||||
import { render } from 'lit';
|
import { render } from 'lit';
|
||||||
|
|
||||||
import './styles/muc-bottom-panel.scss';
|
import './styles/muc-bottom-panel.scss';
|
||||||
|
@ -14,15 +13,15 @@ export default class MUCBottomPanel extends BottomPanel {
|
||||||
|
|
||||||
events = {
|
events = {
|
||||||
'click .hide-occupants': 'hideOccupants',
|
'click .hide-occupants': 'hideOccupants',
|
||||||
'click .send-button': 'onFormSubmitted',
|
'click .send-button': 'sendButtonClicked',
|
||||||
}
|
}
|
||||||
|
|
||||||
async connectedCallback () {
|
async connectedCallback () {
|
||||||
// this.model gets set in the super method and we also wait there for this.model.initialized
|
// this.model gets set in the super method and we also wait there for this.model.initialized
|
||||||
await super.connectedCallback();
|
await super.connectedCallback();
|
||||||
this.debouncedRender = debounce(this.render, 100);
|
this.debouncedRender = debounce(this.render, 100);
|
||||||
this.listenTo(this.model, 'change:composing_spoiler', this.renderMessageForm);
|
|
||||||
this.listenTo(this.model, 'change:hidden_occupants', this.debouncedRender);
|
this.listenTo(this.model, 'change:hidden_occupants', this.debouncedRender);
|
||||||
|
this.listenTo(this.model, 'change:num_unread_general', this.debouncedRender)
|
||||||
this.listenTo(this.model.features, 'change:moderated', this.debouncedRender);
|
this.listenTo(this.model.features, 'change:moderated', this.debouncedRender);
|
||||||
this.listenTo(this.model.occupants, 'add', this.renderIfOwnOccupant)
|
this.listenTo(this.model.occupants, 'add', this.renderIfOwnOccupant)
|
||||||
this.listenTo(this.model.occupants, 'change:role', this.renderIfOwnOccupant);
|
this.listenTo(this.model.occupants, 'change:role', this.renderIfOwnOccupant);
|
||||||
|
@ -33,17 +32,21 @@ export default class MUCBottomPanel extends BottomPanel {
|
||||||
render () {
|
render () {
|
||||||
const entered = this.model.session.get('connection_status') === converse.ROOMSTATUS.ENTERED;
|
const entered = this.model.session.get('connection_status') === converse.ROOMSTATUS.ENTERED;
|
||||||
const can_edit = entered && !(this.model.features.get('moderated') && this.model.getOwnRole() === 'visitor');
|
const can_edit = entered && !(this.model.features.get('moderated') && this.model.getOwnRole() === 'visitor');
|
||||||
render(tpl_muc_bottom_panel({ can_edit, entered, 'model': this.model }), this);
|
render(tpl_muc_bottom_panel({
|
||||||
if (entered && can_edit) {
|
can_edit, entered,
|
||||||
this.renderMessageForm();
|
'model': this.model,
|
||||||
this.initMentionAutoComplete();
|
'viewUnreadMessages': ev => this.viewUnreadMessages(ev)
|
||||||
}
|
}), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderIfOwnOccupant (o) {
|
renderIfOwnOccupant (o) {
|
||||||
(o.get('jid') === _converse.bare_jid) && this.debouncedRender();
|
(o.get('jid') === _converse.bare_jid) && this.debouncedRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sendButtonClicked (ev) {
|
||||||
|
this.querySelector('converse-message-form')?.onFormSubmitted(ev);
|
||||||
|
}
|
||||||
|
|
||||||
getToolbarOptions () {
|
getToolbarOptions () {
|
||||||
return Object.assign(super.getToolbarOptions(), {
|
return Object.assign(super.getToolbarOptions(), {
|
||||||
'is_groupchat': true,
|
'is_groupchat': true,
|
||||||
|
@ -52,49 +55,11 @@ export default class MUCBottomPanel extends BottomPanel {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getAutoCompleteList () {
|
|
||||||
return this.model.getAllKnownNicknames().map(nick => ({ 'label': nick, 'value': `@${nick}` }));
|
|
||||||
}
|
|
||||||
|
|
||||||
initMentionAutoComplete () {
|
|
||||||
this.mention_auto_complete = new _converse.AutoComplete(this, {
|
|
||||||
'auto_first': true,
|
|
||||||
'auto_evaluate': false,
|
|
||||||
'min_chars': api.settings.get('muc_mention_autocomplete_min_chars'),
|
|
||||||
'match_current_word': true,
|
|
||||||
'list': () => this.getAutoCompleteList(),
|
|
||||||
'filter':
|
|
||||||
api.settings.get('muc_mention_autocomplete_filter') == 'contains'
|
|
||||||
? _converse.FILTER_CONTAINS
|
|
||||||
: _converse.FILTER_STARTSWITH,
|
|
||||||
'ac_triggers': ['Tab', '@'],
|
|
||||||
'include_triggers': [],
|
|
||||||
'item': getAutoCompleteListItem
|
|
||||||
});
|
|
||||||
this.mention_auto_complete.on('suggestion-box-selectcomplete', () => (this.auto_completing = false));
|
|
||||||
}
|
|
||||||
|
|
||||||
hideOccupants (ev) {
|
hideOccupants (ev) {
|
||||||
ev?.preventDefault?.();
|
ev?.preventDefault?.();
|
||||||
ev?.stopPropagation?.();
|
ev?.stopPropagation?.();
|
||||||
this.model.save({ 'hidden_occupants': true });
|
this.model.save({ 'hidden_occupants': true });
|
||||||
}
|
}
|
||||||
|
|
||||||
onKeyDown (ev) {
|
|
||||||
if (this.mention_auto_complete.onKeyDown(ev)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
super.onKeyDown(ev);
|
|
||||||
}
|
|
||||||
|
|
||||||
onKeyUp (ev) {
|
|
||||||
this.mention_auto_complete.evaluate(ev);
|
|
||||||
super.onKeyUp(ev);
|
|
||||||
}
|
|
||||||
|
|
||||||
parseMessageForCommands (text) {
|
|
||||||
return parseMessageForMUCCommands(this.model, text);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
api.elements.define('converse-muc-bottom-panel', MUCBottomPanel);
|
api.elements.define('converse-muc-bottom-panel', MUCBottomPanel);
|
||||||
|
|
70
src/plugins/muc-views/message-form.js
Normal file
70
src/plugins/muc-views/message-form.js
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import MessageForm from 'plugins/chatview/message-form.js';
|
||||||
|
import tpl_muc_message_form from './templates/message-form.js';
|
||||||
|
import { _converse, api, converse } from "@converse/headless/core";
|
||||||
|
import { getAutoCompleteListItem, parseMessageForMUCCommands } from './utils.js';
|
||||||
|
|
||||||
|
|
||||||
|
export default class MUCMessageForm extends MessageForm {
|
||||||
|
|
||||||
|
toHTML () {
|
||||||
|
return tpl_muc_message_form(
|
||||||
|
Object.assign(this.model.toJSON(), {
|
||||||
|
'onDrop': ev => this.onDrop(ev),
|
||||||
|
'hint_value': this.querySelector('.spoiler-hint')?.value,
|
||||||
|
'message_value': this.querySelector('.chat-textarea')?.value,
|
||||||
|
'onChange': ev => this.model.set({'draft': ev.target.value}),
|
||||||
|
'onKeyDown': ev => this.onKeyDown(ev),
|
||||||
|
'onKeyUp': ev => this.onKeyUp(ev),
|
||||||
|
'onPaste': ev => this.onPaste(ev),
|
||||||
|
'viewUnreadMessages': ev => this.viewUnreadMessages(ev)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
afterRender () {
|
||||||
|
const entered = this.model.session.get('connection_status') === converse.ROOMSTATUS.ENTERED;
|
||||||
|
const can_edit = entered && !(this.model.features.get('moderated') && this.model.getOwnRole() === 'visitor');
|
||||||
|
if (entered && can_edit) {
|
||||||
|
this.initMentionAutoComplete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initMentionAutoComplete () {
|
||||||
|
this.mention_auto_complete = new _converse.AutoComplete(this, {
|
||||||
|
'auto_first': true,
|
||||||
|
'auto_evaluate': false,
|
||||||
|
'min_chars': api.settings.get('muc_mention_autocomplete_min_chars'),
|
||||||
|
'match_current_word': true,
|
||||||
|
'list': () => this.getAutoCompleteList(),
|
||||||
|
'filter':
|
||||||
|
api.settings.get('muc_mention_autocomplete_filter') == 'contains'
|
||||||
|
? _converse.FILTER_CONTAINS
|
||||||
|
: _converse.FILTER_STARTSWITH,
|
||||||
|
'ac_triggers': ['Tab', '@'],
|
||||||
|
'include_triggers': [],
|
||||||
|
'item': getAutoCompleteListItem
|
||||||
|
});
|
||||||
|
this.mention_auto_complete.on('suggestion-box-selectcomplete', () => (this.auto_completing = false));
|
||||||
|
}
|
||||||
|
|
||||||
|
parseMessageForCommands (text) {
|
||||||
|
return parseMessageForMUCCommands(this.model, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
getAutoCompleteList () {
|
||||||
|
return this.model.getAllKnownNicknames().map(nick => ({ 'label': nick, 'value': `@${nick}` }));
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyDown (ev) {
|
||||||
|
if (this.mention_auto_complete.onKeyDown(ev)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
super.onKeyDown(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyUp (ev) {
|
||||||
|
this.mention_auto_complete.evaluate(ev);
|
||||||
|
super.onKeyUp(ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
api.elements.define('converse-muc-message-form', MUCMessageForm);
|
|
@ -53,7 +53,6 @@ export default class MUCView extends BaseChatView {
|
||||||
*/
|
*/
|
||||||
afterShown () {
|
afterShown () {
|
||||||
if (!this.model.get('hidden') && !this.model.get('minimized')) {
|
if (!this.model.get('hidden') && !this.model.get('minimized')) {
|
||||||
this.model.clearUnreadMsgCounter();
|
|
||||||
this.scrollDown();
|
this.scrollDown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,27 +159,3 @@ converse-muc-destroyed {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@include media-breakpoint-down(sm) {
|
|
||||||
.conversejs {
|
|
||||||
converse-chats.converse-mobile,
|
|
||||||
converse-chats.converse-overlayed,
|
|
||||||
converse-chats.converse-fullscreen {
|
|
||||||
.chatbox {
|
|
||||||
.box-flyout {
|
|
||||||
.chat-head-chatroom {
|
|
||||||
.chatbox-navback {
|
|
||||||
margin-right: 0 !important;
|
|
||||||
.fa-arrow-left {
|
|
||||||
&:before {
|
|
||||||
color: var(--chatroom-head-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { __ } from 'i18n';
|
import { __ } from 'i18n';
|
||||||
import { api } from "@converse/headless/core";
|
import { api } from "@converse/headless/core";
|
||||||
import { html } from "lit";
|
import { html } from "lit";
|
||||||
|
import { resetElementHeight } from 'plugins/chatview/utils.js';
|
||||||
|
|
||||||
|
|
||||||
export default (o) => {
|
export default (o) => {
|
||||||
|
@ -15,16 +16,14 @@ export default (o) => {
|
||||||
<input type="submit" class="btn btn-primary" name="join" value="Join"/>
|
<input type="submit" class="btn btn-primary" name="join" value="Join"/>
|
||||||
</form>
|
</form>
|
||||||
<form class="sendXMPPMessage">
|
<form class="sendXMPPMessage">
|
||||||
<span class="chat-toolbar no-text-select"></span>
|
|
||||||
<input type="text" placeholder="${label_spoiler_hint || ''}" value="${o.hint_value || ''}" class="${o.composing_spoiler ? '' : 'hidden'} spoiler-hint"/>
|
<input type="text" placeholder="${label_spoiler_hint || ''}" value="${o.hint_value || ''}" class="${o.composing_spoiler ? '' : 'hidden'} spoiler-hint"/>
|
||||||
|
|
||||||
<div class="suggestion-box">
|
<div class="suggestion-box">
|
||||||
<ul class="suggestion-box__results suggestion-box__results--above" hidden=""></ul>
|
<ul class="suggestion-box__results suggestion-box__results--above" hidden=""></ul>
|
||||||
<textarea
|
<textarea
|
||||||
autofocus
|
autofocus
|
||||||
type="text"
|
type="text"
|
||||||
@drop=${o.onDrop}
|
@drop=${o.onDrop}
|
||||||
@input=${o.inputChanged}
|
@input=${resetElementHeight}
|
||||||
@keydown=${o.onKeyDown}
|
@keydown=${o.onKeyDown}
|
||||||
@keyup=${o.onKeyUp}
|
@keyup=${o.onKeyUp}
|
||||||
@paste=${o.onPaste}
|
@paste=${o.onPaste}
|
|
@ -1,19 +1,46 @@
|
||||||
|
import '../message-form.js';
|
||||||
|
import 'shared/chat/toolbar.js';
|
||||||
import tpl_muc_nickname_form from './muc-nickname-form.js';
|
import tpl_muc_nickname_form from './muc-nickname-form.js';
|
||||||
import { __ } from 'i18n';
|
import { __ } from 'i18n';
|
||||||
import { api, converse } from "@converse/headless/core";
|
import { api, converse } from "@converse/headless/core";
|
||||||
import { html } from "lit";
|
import { html } from "lit";
|
||||||
|
|
||||||
|
|
||||||
const tpl_can_edit = () => html`
|
const tpl_can_edit = (o) => {
|
||||||
<div class="emoji-picker__container dropup"></div>
|
const message_limit = api.settings.get('message_limit');
|
||||||
<div class="message-form-container">`;
|
const show_call_button = api.settings.get('visible_toolbar_buttons').call;
|
||||||
|
const show_emoji_button = api.settings.get('visible_toolbar_buttons').emoji;
|
||||||
|
const show_send_button = api.settings.get('show_send_button');
|
||||||
|
const show_spoiler_button = api.settings.get('visible_toolbar_buttons').spoiler;
|
||||||
|
const show_toolbar = api.settings.get('show_toolbar');
|
||||||
|
return html`
|
||||||
|
${show_toolbar ? html`
|
||||||
|
<converse-chat-toolbar
|
||||||
|
class="chat-toolbar no-text-select"
|
||||||
|
.model=${o.model}
|
||||||
|
?composing_spoiler="${o.model.get('composing_spoiler')}"
|
||||||
|
?hidden_occupants="${o.model.get('hidden_occupants')}"
|
||||||
|
?is_groupchat="${o.model.get('is_groupchat')}"
|
||||||
|
?show_call_button="${show_call_button}"
|
||||||
|
?show_emoji_button="${show_emoji_button}"
|
||||||
|
?show_occupants_toggle="${o.model.get('show_occupants_toggle')}"
|
||||||
|
?show_send_button="${show_send_button}"
|
||||||
|
?show_spoiler_button="${show_spoiler_button}"
|
||||||
|
?show_toolbar="${show_toolbar}"
|
||||||
|
message_limit="${message_limit}"></converse-chat-toolbar>` : '' }
|
||||||
|
<converse-muc-message-form jid=${o.model.get('jid')}></converse-muc-message-form>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export default (o) => {
|
export default (o) => {
|
||||||
|
const unread_msgs = __('You have unread messages');
|
||||||
const conn_status = o.model.session.get('connection_status');
|
const conn_status = o.model.session.get('connection_status');
|
||||||
const i18n_not_allowed = __("You're not allowed to send messages in this room");
|
const i18n_not_allowed = __("You're not allowed to send messages in this room");
|
||||||
if (conn_status === converse.ROOMSTATUS.ENTERED) {
|
if (conn_status === converse.ROOMSTATUS.ENTERED) {
|
||||||
return (o.can_edit) ? tpl_can_edit() : html`<span class="muc-bottom-panel muc-bottom-panel--muted">${i18n_not_allowed}</span>`;
|
return html`
|
||||||
|
${ o.model.get('scrolled') && o.model.get('num_unread_general') ?
|
||||||
|
html`<div class="new-msgs-indicator" @click=${ev => o.viewUnreadMessages(ev)}>▼ ${ unread_msgs } ▼</div>` : '' }
|
||||||
|
${(o.can_edit) ? tpl_can_edit(o) : html`<span class="muc-bottom-panel muc-bottom-panel--muted">${i18n_not_allowed}</span>`}`;
|
||||||
} else if (conn_status == converse.ROOMSTATUS.NICKNAME_REQUIRED) {
|
} else if (conn_status == converse.ROOMSTATUS.NICKNAME_REQUIRED) {
|
||||||
if (api.settings.get('muc_show_logs_before_join')) {
|
if (api.settings.get('muc_show_logs_before_join')) {
|
||||||
return html`<span class="muc-bottom-panel muc-bottom-panel--nickname">${tpl_muc_nickname_form(o.model)}</span>`;
|
return html`<span class="muc-bottom-panel muc-bottom-panel--nickname">${tpl_muc_nickname_form(o.model)}</span>`;
|
||||||
|
|
|
@ -48,10 +48,10 @@ describe("The nickname autocomplete feature", function () {
|
||||||
'keyCode': 50,
|
'keyCode': 50,
|
||||||
'key': '@'
|
'key': '@'
|
||||||
};
|
};
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown(at_event);
|
message_form.onKeyDown(at_event);
|
||||||
textarea.value = '@';
|
textarea.value = '@';
|
||||||
bottom_panel.onKeyUp(at_event);
|
message_form.onKeyUp(at_event);
|
||||||
|
|
||||||
await u.waitUntil(() => view.querySelectorAll('.suggestion-box__results li').length === 4);
|
await u.waitUntil(() => view.querySelectorAll('.suggestion-box__results li').length === 4);
|
||||||
expect(view.querySelector('.suggestion-box__results li:first-child').textContent).toBe('dick');
|
expect(view.querySelector('.suggestion-box__results li:first-child').textContent).toBe('dick');
|
||||||
|
@ -102,11 +102,11 @@ describe("The nickname autocomplete feature", function () {
|
||||||
'keyCode': 50,
|
'keyCode': 50,
|
||||||
'key': '@'
|
'key': '@'
|
||||||
};
|
};
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
textarea.value = '\n'
|
textarea.value = '\n'
|
||||||
bottom_panel.onKeyDown(at_event);
|
message_form.onKeyDown(at_event);
|
||||||
textarea.value = '\n@';
|
textarea.value = '\n@';
|
||||||
bottom_panel.onKeyUp(at_event);
|
message_form.onKeyUp(at_event);
|
||||||
|
|
||||||
await u.waitUntil(() => view.querySelectorAll('.suggestion-box__results li').length === 4);
|
await u.waitUntil(() => view.querySelectorAll('.suggestion-box__results li').length === 4);
|
||||||
expect(view.querySelector('.suggestion-box__results li:first-child').textContent).toBe('dick');
|
expect(view.querySelector('.suggestion-box__results li:first-child').textContent).toBe('dick');
|
||||||
|
@ -159,10 +159,10 @@ describe("The nickname autocomplete feature", function () {
|
||||||
'key': '@'
|
'key': '@'
|
||||||
};
|
};
|
||||||
textarea.value = '('
|
textarea.value = '('
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown(at_event);
|
message_form.onKeyDown(at_event);
|
||||||
textarea.value = '(@';
|
textarea.value = '(@';
|
||||||
bottom_panel.onKeyUp(at_event);
|
message_form.onKeyUp(at_event);
|
||||||
|
|
||||||
await u.waitUntil(() => view.querySelectorAll('.suggestion-box__results li').length === 4);
|
await u.waitUntil(() => view.querySelectorAll('.suggestion-box__results li').length === 4);
|
||||||
expect(view.querySelector('.suggestion-box__results li:first-child').textContent).toBe('dick');
|
expect(view.querySelector('.suggestion-box__results li:first-child').textContent).toBe('dick');
|
||||||
|
@ -201,11 +201,11 @@ describe("The nickname autocomplete feature", function () {
|
||||||
'key': '@'
|
'key': '@'
|
||||||
};
|
};
|
||||||
|
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
// Test that results are sorted by query index
|
// Test that results are sorted by query index
|
||||||
bottom_panel.onKeyDown(at_event);
|
message_form.onKeyDown(at_event);
|
||||||
textarea.value = '@ber';
|
textarea.value = '@ber';
|
||||||
bottom_panel.onKeyUp(at_event);
|
message_form.onKeyUp(at_event);
|
||||||
await u.waitUntil(() => view.querySelectorAll('.suggestion-box__results li').length === 3);
|
await u.waitUntil(() => view.querySelectorAll('.suggestion-box__results li').length === 3);
|
||||||
expect(view.querySelector('.suggestion-box__results li:first-child').textContent).toBe('bernard');
|
expect(view.querySelector('.suggestion-box__results li:first-child').textContent).toBe('bernard');
|
||||||
expect(view.querySelector('.suggestion-box__results li:nth-child(2)').textContent).toBe('naber');
|
expect(view.querySelector('.suggestion-box__results li:nth-child(2)').textContent).toBe('naber');
|
||||||
|
@ -213,7 +213,7 @@ describe("The nickname autocomplete feature", function () {
|
||||||
|
|
||||||
// Test that when the query index is equal, results should be sorted by length
|
// Test that when the query index is equal, results should be sorted by length
|
||||||
textarea.value = '@jo';
|
textarea.value = '@jo';
|
||||||
bottom_panel.onKeyUp(at_event);
|
message_form.onKeyUp(at_event);
|
||||||
await u.waitUntil(() => view.querySelectorAll('.suggestion-box__results li').length === 2);
|
await u.waitUntil(() => view.querySelectorAll('.suggestion-box__results li').length === 2);
|
||||||
expect(view.querySelector('.suggestion-box__results li:first-child').textContent).toBe('john');
|
expect(view.querySelector('.suggestion-box__results li:first-child').textContent).toBe('john');
|
||||||
expect(view.querySelector('.suggestion-box__results li:nth-child(2)').textContent).toBe('jones');
|
expect(view.querySelector('.suggestion-box__results li:nth-child(2)').textContent).toBe('jones');
|
||||||
|
@ -250,9 +250,9 @@ describe("The nickname autocomplete feature", function () {
|
||||||
'keyCode': 9,
|
'keyCode': 9,
|
||||||
'key': 'Tab'
|
'key': 'Tab'
|
||||||
}
|
}
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown(tab_event);
|
message_form.onKeyDown(tab_event);
|
||||||
bottom_panel.onKeyUp(tab_event);
|
message_form.onKeyUp(tab_event);
|
||||||
await u.waitUntil(() => view.querySelector('.suggestion-box__results').hidden === false);
|
await u.waitUntil(() => view.querySelector('.suggestion-box__results').hidden === false);
|
||||||
expect(view.querySelectorAll('.suggestion-box__results li').length).toBe(1);
|
expect(view.querySelectorAll('.suggestion-box__results li').length).toBe(1);
|
||||||
expect(view.querySelector('.suggestion-box__results li').textContent).toBe('some1');
|
expect(view.querySelector('.suggestion-box__results li').textContent).toBe('some1');
|
||||||
|
@ -264,9 +264,9 @@ describe("The nickname autocomplete feature", function () {
|
||||||
}
|
}
|
||||||
for (var i=0; i<3; i++) {
|
for (var i=0; i<3; i++) {
|
||||||
// Press backspace 3 times to remove "som"
|
// Press backspace 3 times to remove "som"
|
||||||
bottom_panel.onKeyDown(backspace_event);
|
message_form.onKeyDown(backspace_event);
|
||||||
textarea.value = textarea.value.slice(0, textarea.value.length-1)
|
textarea.value = textarea.value.slice(0, textarea.value.length-1)
|
||||||
bottom_panel.onKeyUp(backspace_event);
|
message_form.onKeyUp(backspace_event);
|
||||||
}
|
}
|
||||||
await u.waitUntil(() => view.querySelector('.suggestion-box__results').hidden === true);
|
await u.waitUntil(() => view.querySelector('.suggestion-box__results').hidden === true);
|
||||||
|
|
||||||
|
@ -283,8 +283,8 @@ describe("The nickname autocomplete feature", function () {
|
||||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||||
|
|
||||||
textarea.value = "hello s s";
|
textarea.value = "hello s s";
|
||||||
bottom_panel.onKeyDown(tab_event);
|
message_form.onKeyDown(tab_event);
|
||||||
bottom_panel.onKeyUp(tab_event);
|
message_form.onKeyUp(tab_event);
|
||||||
await u.waitUntil(() => view.querySelector('.suggestion-box__results').hidden === false);
|
await u.waitUntil(() => view.querySelector('.suggestion-box__results').hidden === false);
|
||||||
expect(view.querySelectorAll('.suggestion-box__results li').length).toBe(2);
|
expect(view.querySelectorAll('.suggestion-box__results li').length).toBe(2);
|
||||||
|
|
||||||
|
@ -294,13 +294,13 @@ describe("The nickname autocomplete feature", function () {
|
||||||
'stopPropagation': function stopPropagation () {},
|
'stopPropagation': function stopPropagation () {},
|
||||||
'keyCode': 38
|
'keyCode': 38
|
||||||
}
|
}
|
||||||
bottom_panel.onKeyDown(up_arrow_event);
|
message_form.onKeyDown(up_arrow_event);
|
||||||
bottom_panel.onKeyUp(up_arrow_event);
|
message_form.onKeyUp(up_arrow_event);
|
||||||
expect(view.querySelectorAll('.suggestion-box__results li').length).toBe(2);
|
expect(view.querySelectorAll('.suggestion-box__results li').length).toBe(2);
|
||||||
expect(view.querySelector('.suggestion-box__results li[aria-selected="false"]').textContent).toBe('some1');
|
expect(view.querySelector('.suggestion-box__results li[aria-selected="false"]').textContent).toBe('some1');
|
||||||
expect(view.querySelector('.suggestion-box__results li[aria-selected="true"]').textContent).toBe('some2');
|
expect(view.querySelector('.suggestion-box__results li[aria-selected="true"]').textContent).toBe('some2');
|
||||||
|
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
'target': textarea,
|
'target': textarea,
|
||||||
'preventDefault': function preventDefault () {},
|
'preventDefault': function preventDefault () {},
|
||||||
'stopPropagation': function stopPropagation () {},
|
'stopPropagation': function stopPropagation () {},
|
||||||
|
@ -321,12 +321,12 @@ describe("The nickname autocomplete feature", function () {
|
||||||
});
|
});
|
||||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||||
textarea.value = "hello z";
|
textarea.value = "hello z";
|
||||||
bottom_panel.onKeyDown(tab_event);
|
message_form.onKeyDown(tab_event);
|
||||||
bottom_panel.onKeyUp(tab_event);
|
message_form.onKeyUp(tab_event);
|
||||||
await u.waitUntil(() => view.querySelector('.suggestion-box__results').hidden === false);
|
await u.waitUntil(() => view.querySelector('.suggestion-box__results').hidden === false);
|
||||||
|
|
||||||
bottom_panel.onKeyDown(tab_event);
|
message_form.onKeyDown(tab_event);
|
||||||
bottom_panel.onKeyUp(tab_event);
|
message_form.onKeyUp(tab_event);
|
||||||
await u.waitUntil(() => textarea.value === 'hello @z3r0 ');
|
await u.waitUntil(() => textarea.value === 'hello @z3r0 ');
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
@ -361,10 +361,10 @@ describe("The nickname autocomplete feature", function () {
|
||||||
'keyCode': 8,
|
'keyCode': 8,
|
||||||
'key': 'Backspace'
|
'key': 'Backspace'
|
||||||
}
|
}
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown(backspace_event);
|
message_form.onKeyDown(backspace_event);
|
||||||
textarea.value = "hello @some1"; // Mimic backspace
|
textarea.value = "hello @some1"; // Mimic backspace
|
||||||
bottom_panel.onKeyUp(backspace_event);
|
message_form.onKeyUp(backspace_event);
|
||||||
await u.waitUntil(() => view.querySelector('.suggestion-box__results').hidden === false);
|
await u.waitUntil(() => view.querySelector('.suggestion-box__results').hidden === false);
|
||||||
expect(view.querySelectorAll('.suggestion-box__results li').length).toBe(1);
|
expect(view.querySelectorAll('.suggestion-box__results li').length).toBe(1);
|
||||||
expect(view.querySelector('.suggestion-box__results li').textContent).toBe('some1');
|
expect(view.querySelector('.suggestion-box__results li').textContent).toBe('some1');
|
||||||
|
|
|
@ -169,15 +169,15 @@ describe("A Groupchat Message", function () {
|
||||||
const view = _converse.api.chatviews.get(muc_jid);
|
const view = _converse.api.chatviews.get(muc_jid);
|
||||||
const textarea = await u.waitUntil(() => view.querySelector('textarea.chat-textarea'));
|
const textarea = await u.waitUntil(() => view.querySelector('textarea.chat-textarea'));
|
||||||
expect(textarea.value).toBe('');
|
expect(textarea.value).toBe('');
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
keyCode: 38 // Up arrow
|
keyCode: 38 // Up arrow
|
||||||
});
|
});
|
||||||
expect(textarea.value).toBe('');
|
expect(textarea.value).toBe('');
|
||||||
|
|
||||||
textarea.value = 'But soft, what light through yonder airlock breaks?';
|
textarea.value = 'But soft, what light through yonder airlock breaks?';
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
|
@ -188,7 +188,7 @@ describe("A Groupchat Message", function () {
|
||||||
|
|
||||||
const first_msg = view.model.messages.findWhere({'message': 'But soft, what light through yonder airlock breaks?'});
|
const first_msg = view.model.messages.findWhere({'message': 'But soft, what light through yonder airlock breaks?'});
|
||||||
expect(textarea.value).toBe('');
|
expect(textarea.value).toBe('');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
keyCode: 38 // Up arrow
|
keyCode: 38 // Up arrow
|
||||||
});
|
});
|
||||||
|
@ -200,7 +200,7 @@ describe("A Groupchat Message", function () {
|
||||||
spyOn(_converse.connection, 'send');
|
spyOn(_converse.connection, 'send');
|
||||||
const new_text = 'But soft, what light through yonder window breaks?'
|
const new_text = 'But soft, what light through yonder window breaks?'
|
||||||
textarea.value = new_text;
|
textarea.value = new_text;
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
|
@ -245,7 +245,7 @@ describe("A Groupchat Message", function () {
|
||||||
|
|
||||||
// Test that pressing the down arrow cancels message correction
|
// Test that pressing the down arrow cancels message correction
|
||||||
expect(textarea.value).toBe('');
|
expect(textarea.value).toBe('');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
keyCode: 38 // Up arrow
|
keyCode: 38 // Up arrow
|
||||||
});
|
});
|
||||||
|
@ -254,7 +254,7 @@ describe("A Groupchat Message", function () {
|
||||||
expect(view.querySelectorAll('.chat-msg').length).toBe(2);
|
expect(view.querySelectorAll('.chat-msg').length).toBe(2);
|
||||||
await u.waitUntil(() => u.hasClass('correcting', view.querySelector('.chat-msg')), 500);
|
await u.waitUntil(() => u.hasClass('correcting', view.querySelector('.chat-msg')), 500);
|
||||||
expect(textarea.value).toBe('But soft, what light through yonder window breaks?');
|
expect(textarea.value).toBe('But soft, what light through yonder window breaks?');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
keyCode: 40 // Down arrow
|
keyCode: 40 // Down arrow
|
||||||
});
|
});
|
||||||
|
|
|
@ -109,8 +109,8 @@ describe("An incoming groupchat message", function () {
|
||||||
'stopPropagation': function stopPropagation () {},
|
'stopPropagation': function stopPropagation () {},
|
||||||
'keyCode': 13 // Enter
|
'keyCode': 13 // Enter
|
||||||
}
|
}
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown(enter_event);
|
message_form.onKeyDown(enter_event);
|
||||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
|
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
|
||||||
|
|
||||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
|
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
|
||||||
|
@ -363,8 +363,8 @@ describe("A sent groupchat message", function () {
|
||||||
'stopPropagation': function stopPropagation () {},
|
'stopPropagation': function stopPropagation () {},
|
||||||
'keyCode': 13 // Enter
|
'keyCode': 13 // Enter
|
||||||
}
|
}
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown(enter_event);
|
message_form.onKeyDown(enter_event);
|
||||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
|
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
|
||||||
const sent_stanzas = _converse.connection.sent_stanzas;
|
const sent_stanzas = _converse.connection.sent_stanzas;
|
||||||
const msg = await u.waitUntil(() => sent_stanzas.filter(s => s.nodeName.toLowerCase() === 'message').pop());
|
const msg = await u.waitUntil(() => sent_stanzas.filter(s => s.nodeName.toLowerCase() === 'message').pop());
|
||||||
|
@ -423,8 +423,8 @@ describe("A sent groupchat message", function () {
|
||||||
'stopPropagation': function stopPropagation () {},
|
'stopPropagation': function stopPropagation () {},
|
||||||
'keyCode': 13 // Enter
|
'keyCode': 13 // Enter
|
||||||
}
|
}
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown(enter_event);
|
message_form.onKeyDown(enter_event);
|
||||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
|
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
|
||||||
|
|
||||||
const last_msg_sel = 'converse-chat-message:last-child .chat-msg__text';
|
const last_msg_sel = 'converse-chat-message:last-child .chat-msg__text';
|
||||||
|
@ -457,7 +457,7 @@ describe("A sent groupchat message", function () {
|
||||||
await u.waitUntil(() => u.hasClass('correcting', view.querySelector('.chat-msg')), 500);
|
await u.waitUntil(() => u.hasClass('correcting', view.querySelector('.chat-msg')), 500);
|
||||||
|
|
||||||
textarea.value = 'hello @z3r0 @gibson @sw0rdf1sh, how are you?';
|
textarea.value = 'hello @z3r0 @gibson @sw0rdf1sh, how are you?';
|
||||||
bottom_panel.onKeyDown(enter_event);
|
message_form.onKeyDown(enter_event);
|
||||||
await u.waitUntil(() => view.querySelector('.chat-msg__text').textContent ===
|
await u.waitUntil(() => view.querySelector('.chat-msg__text').textContent ===
|
||||||
'hello z3r0 gibson sw0rdf1sh, how are you?', 500);
|
'hello z3r0 gibson sw0rdf1sh, how are you?', 500);
|
||||||
|
|
||||||
|
@ -507,8 +507,8 @@ describe("A sent groupchat message", function () {
|
||||||
'stopPropagation': function stopPropagation () {},
|
'stopPropagation': function stopPropagation () {},
|
||||||
'keyCode': 13 // Enter
|
'keyCode': 13 // Enter
|
||||||
}
|
}
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown(enter_event);
|
message_form.onKeyDown(enter_event);
|
||||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
|
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
|
||||||
|
|
||||||
const msg = _converse.connection.send.calls.all()[0].args[0];
|
const msg = _converse.connection.send.calls.all()[0].args[0];
|
||||||
|
@ -542,8 +542,8 @@ describe("A sent groupchat message", function () {
|
||||||
'stopPropagation': function stopPropagation () {},
|
'stopPropagation': function stopPropagation () {},
|
||||||
'keyCode': 13 // Enter
|
'keyCode': 13 // Enter
|
||||||
}
|
}
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown(enter_event);
|
message_form.onKeyDown(enter_event);
|
||||||
const message = await u.waitUntil(() => view.querySelector('.chat-msg__text'));
|
const message = await u.waitUntil(() => view.querySelector('.chat-msg__text'));
|
||||||
expect(message.innerHTML.replace(/<!-.*?->/g, '')).toEqual(
|
expect(message.innerHTML.replace(/<!-.*?->/g, '')).toEqual(
|
||||||
`Welcome <span class="mention">gibson</span> <span title=":poop:">💩</span> `+
|
`Welcome <span class="mention">gibson</span> <span title=":poop:">💩</span> `+
|
||||||
|
|
|
@ -11,8 +11,8 @@ async function openModtools (_converse, view) {
|
||||||
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
||||||
textarea.value = '/modtools';
|
textarea.value = '/modtools';
|
||||||
const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
|
const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown(enter);
|
message_form.onKeyDown(enter);
|
||||||
const modal = await u.waitUntil(() => _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);
|
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||||
return modal;
|
return modal;
|
||||||
|
@ -256,8 +256,8 @@ describe("The groupchat moderator tool", function () {
|
||||||
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
||||||
textarea.value = '/modtools';
|
textarea.value = '/modtools';
|
||||||
const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
|
const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown(enter);
|
message_form.onKeyDown(enter);
|
||||||
|
|
||||||
const modal = await u.waitUntil(() => _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);
|
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||||
|
@ -455,8 +455,8 @@ describe("The groupchat moderator tool", function () {
|
||||||
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
||||||
textarea.value = '/modtools';
|
textarea.value = '/modtools';
|
||||||
const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
|
const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown(enter);
|
message_form.onKeyDown(enter);
|
||||||
|
|
||||||
const modal = await u.waitUntil(() => _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});
|
const occupant = view.model.occupants.findWhere({'jid': _converse.bare_jid});
|
||||||
|
|
|
@ -25,8 +25,8 @@ describe("A Groupchat Message", function () {
|
||||||
'stopPropagation': function stopPropagation () {},
|
'stopPropagation': function stopPropagation () {},
|
||||||
'keyCode': 13 // Enter
|
'keyCode': 13 // Enter
|
||||||
}
|
}
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown(enter_event);
|
message_form.onKeyDown(enter_event);
|
||||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||||
|
|
||||||
const msg = view.model.messages.at(0);
|
const msg = view.model.messages.at(0);
|
||||||
|
@ -514,8 +514,8 @@ describe("A Groupchat Message", function () {
|
||||||
const view = _converse.api.chatviews.get(muc_jid);
|
const view = _converse.api.chatviews.get(muc_jid);
|
||||||
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
||||||
textarea.value = 'But soft, what light through yonder airlock breaks?';
|
textarea.value = 'But soft, what light through yonder airlock breaks?';
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
|
@ -589,8 +589,8 @@ describe("A Groupchat Message", function () {
|
||||||
const view = _converse.api.chatviews.get(muc_jid);
|
const view = _converse.api.chatviews.get(muc_jid);
|
||||||
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
||||||
textarea.value = 'But soft, what light through yonder airlock breaks?';
|
textarea.value = 'But soft, what light through yonder airlock breaks?';
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
|
|
|
@ -15,8 +15,8 @@ describe("Chatrooms", function () {
|
||||||
const view = _converse.chatboxviews.get(muc_jid);
|
const view = _converse.chatboxviews.get(muc_jid);
|
||||||
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
||||||
textarea.value = '/register';
|
textarea.value = '/register';
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13
|
keyCode: 13
|
||||||
|
|
|
@ -281,8 +281,7 @@ describe("Groupchats", function () {
|
||||||
_converse.connection._dataRecv(mock.createRequest(message));
|
_converse.connection._dataRecv(mock.createRequest(message));
|
||||||
|
|
||||||
await u.waitUntil(() => view.model.messages.length);
|
await u.waitUntil(() => view.model.messages.length);
|
||||||
const chat_new_msgs_indicator = view.querySelector('.new-msgs-indicator');
|
const chat_new_msgs_indicator = await u.waitUntil(() => view.querySelector('.new-msgs-indicator'));
|
||||||
await u.waitUntil(() => u.isVisible(chat_new_msgs_indicator));
|
|
||||||
chat_new_msgs_indicator.click();
|
chat_new_msgs_indicator.click();
|
||||||
expect(view.model.get('scrolled')).toBeFalsy();
|
expect(view.model.get('scrolled')).toBeFalsy();
|
||||||
await u.waitUntil(() => !u.isVisible(chat_new_msgs_indicator));
|
await u.waitUntil(() => !u.isVisible(chat_new_msgs_indicator));
|
||||||
|
@ -1895,8 +1894,8 @@ describe("Groupchats", function () {
|
||||||
const text = 'This is a sent message';
|
const text = 'This is a sent message';
|
||||||
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
||||||
textarea.value = text;
|
textarea.value = text;
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13
|
keyCode: 13
|
||||||
|
@ -2753,8 +2752,8 @@ describe("Groupchats", function () {
|
||||||
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
||||||
const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
|
const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
|
||||||
textarea.value = '/help';
|
textarea.value = '/help';
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown(enter);
|
message_form.onKeyDown(enter);
|
||||||
|
|
||||||
await u.waitUntil(() => sizzle('converse-chat-help .chat-info', view).length);
|
await u.waitUntil(() => sizzle('converse-chat-help .chat-info', view).length);
|
||||||
let chat_help_el = view.querySelector('converse-chat-help');
|
let chat_help_el = view.querySelector('converse-chat-help');
|
||||||
|
@ -2788,7 +2787,7 @@ describe("Groupchats", function () {
|
||||||
await u.waitUntil(() => view.querySelector('converse-chat-help') === null);
|
await u.waitUntil(() => view.querySelector('converse-chat-help') === null);
|
||||||
|
|
||||||
textarea.value = '/help';
|
textarea.value = '/help';
|
||||||
bottom_panel.onKeyDown(enter);
|
message_form.onKeyDown(enter);
|
||||||
chat_help_el = await u.waitUntil(() => view.querySelector('converse-chat-help'));
|
chat_help_el = await u.waitUntil(() => view.querySelector('converse-chat-help'));
|
||||||
info_messages = sizzle('.chat-info', chat_help_el);
|
info_messages = sizzle('.chat-info', chat_help_el);
|
||||||
expect(info_messages.length).toBe(18);
|
expect(info_messages.length).toBe(18);
|
||||||
|
@ -2803,7 +2802,7 @@ describe("Groupchats", function () {
|
||||||
await u.waitUntil(() => view.querySelector('converse-chat-help') === null);
|
await u.waitUntil(() => view.querySelector('converse-chat-help') === null);
|
||||||
|
|
||||||
textarea.value = '/help';
|
textarea.value = '/help';
|
||||||
bottom_panel.onKeyDown(enter);
|
message_form.onKeyDown(enter);
|
||||||
chat_help_el = await u.waitUntil(() => view.querySelector('converse-chat-help'));
|
chat_help_el = await u.waitUntil(() => view.querySelector('converse-chat-help'));
|
||||||
info_messages = sizzle('.chat-info', chat_help_el);
|
info_messages = sizzle('.chat-info', chat_help_el);
|
||||||
expect(info_messages.length).toBe(9);
|
expect(info_messages.length).toBe(9);
|
||||||
|
@ -2818,7 +2817,7 @@ describe("Groupchats", function () {
|
||||||
// Role changes causes rerender, so we need to get the new textarea
|
// Role changes causes rerender, so we need to get the new textarea
|
||||||
|
|
||||||
textarea.value = '/help';
|
textarea.value = '/help';
|
||||||
bottom_panel.onKeyDown(enter);
|
message_form.onKeyDown(enter);
|
||||||
await u.waitUntil(() => view.model.get('show_help_messages'));
|
await u.waitUntil(() => view.model.get('show_help_messages'));
|
||||||
chat_help_el = await u.waitUntil(() => view.querySelector('converse-chat-help'));
|
chat_help_el = await u.waitUntil(() => view.querySelector('converse-chat-help'));
|
||||||
info_messages = sizzle('.chat-info', chat_help_el);
|
info_messages = sizzle('.chat-info', chat_help_el);
|
||||||
|
@ -2833,7 +2832,7 @@ describe("Groupchats", function () {
|
||||||
await u.waitUntil(() => view.querySelector('converse-chat-help') === null);
|
await u.waitUntil(() => view.querySelector('converse-chat-help') === null);
|
||||||
|
|
||||||
textarea.value = '/help';
|
textarea.value = '/help';
|
||||||
bottom_panel.onKeyDown(enter);
|
message_form.onKeyDown(enter);
|
||||||
chat_help_el = await u.waitUntil(() => view.querySelector('converse-chat-help'));
|
chat_help_el = await u.waitUntil(() => view.querySelector('converse-chat-help'));
|
||||||
info_messages = sizzle('.chat-info', chat_help_el);
|
info_messages = sizzle('.chat-info', chat_help_el);
|
||||||
expect(info_messages.length).toBe(7);
|
expect(info_messages.length).toBe(7);
|
||||||
|
@ -2851,10 +2850,10 @@ describe("Groupchats", function () {
|
||||||
const enter = { 'target': textarea, 'preventDefault': function () {}, 'keyCode': 13 };
|
const enter = { 'target': textarea, 'preventDefault': function () {}, 'keyCode': 13 };
|
||||||
spyOn(window, 'confirm').and.callFake(() => true);
|
spyOn(window, 'confirm').and.callFake(() => true);
|
||||||
textarea.value = '/clear';
|
textarea.value = '/clear';
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown(enter);
|
message_form.onKeyDown(enter);
|
||||||
textarea.value = '/help';
|
textarea.value = '/help';
|
||||||
bottom_panel.onKeyDown(enter);
|
message_form.onKeyDown(enter);
|
||||||
|
|
||||||
await u.waitUntil(() => sizzle('.chat-info:not(.chat-event)', view).length);
|
await u.waitUntil(() => sizzle('.chat-info:not(.chat-event)', view).length);
|
||||||
const info_messages = sizzle('.chat-info:not(.chat-event)', view);
|
const info_messages = sizzle('.chat-info:not(.chat-event)', view);
|
||||||
|
@ -2910,8 +2909,8 @@ describe("Groupchats", function () {
|
||||||
// First check that an error message appears when a
|
// First check that an error message appears when a
|
||||||
// non-existent nick is used.
|
// non-existent nick is used.
|
||||||
textarea.value = '/member chris Welcome to the club!';
|
textarea.value = '/member chris Welcome to the club!';
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13
|
keyCode: 13
|
||||||
|
@ -2923,7 +2922,7 @@ describe("Groupchats", function () {
|
||||||
|
|
||||||
// Now test with an existing nick
|
// Now test with an existing nick
|
||||||
textarea.value = '/member marc Welcome to the club!';
|
textarea.value = '/member marc Welcome to the club!';
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13
|
keyCode: 13
|
||||||
|
@ -3030,8 +3029,8 @@ describe("Groupchats", function () {
|
||||||
// Check the alias /topic
|
// Check the alias /topic
|
||||||
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
||||||
textarea.value = '/topic This is the groupchat subject';
|
textarea.value = '/topic This is the groupchat subject';
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13
|
keyCode: 13
|
||||||
|
@ -3041,7 +3040,7 @@ describe("Groupchats", function () {
|
||||||
|
|
||||||
// Check /subject
|
// Check /subject
|
||||||
textarea.value = '/subject This is a new subject';
|
textarea.value = '/subject This is a new subject';
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13
|
keyCode: 13
|
||||||
|
@ -3055,7 +3054,7 @@ describe("Groupchats", function () {
|
||||||
|
|
||||||
// Check case insensitivity
|
// Check case insensitivity
|
||||||
textarea.value = '/Subject This is yet another subject';
|
textarea.value = '/Subject This is yet another subject';
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13
|
keyCode: 13
|
||||||
|
@ -3068,7 +3067,7 @@ describe("Groupchats", function () {
|
||||||
|
|
||||||
// Check unsetting the topic
|
// Check unsetting the topic
|
||||||
textarea.value = '/topic';
|
textarea.value = '/topic';
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13
|
keyCode: 13
|
||||||
|
@ -3085,9 +3084,9 @@ describe("Groupchats", function () {
|
||||||
const view = _converse.chatboxviews.get('lounge@montague.lit');
|
const view = _converse.chatboxviews.get('lounge@montague.lit');
|
||||||
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
||||||
textarea.value = '/clear';
|
textarea.value = '/clear';
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
|
||||||
spyOn(window, 'confirm').and.callFake(() => false);
|
spyOn(window, 'confirm').and.callFake(() => false);
|
||||||
bottom_panel.onKeyDown({
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13
|
keyCode: 13
|
||||||
|
@ -3123,8 +3122,8 @@ describe("Groupchats", function () {
|
||||||
|
|
||||||
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
||||||
textarea.value = '/owner';
|
textarea.value = '/owner';
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13
|
keyCode: 13
|
||||||
|
@ -3142,7 +3141,7 @@ describe("Groupchats", function () {
|
||||||
// again via triggering Event doesn't work for some weird
|
// again via triggering Event doesn't work for some weird
|
||||||
// reason.
|
// reason.
|
||||||
textarea.value = '/owner nobody You\'re responsible';
|
textarea.value = '/owner nobody You\'re responsible';
|
||||||
bottom_panel.onFormSubmitted(new Event('submit'));
|
message_form.onFormSubmitted(new Event('submit'));
|
||||||
await u.waitUntil(() => view.querySelectorAll('.chat-error').length === 2);
|
await u.waitUntil(() => view.querySelectorAll('.chat-error').length === 2);
|
||||||
expect(Array.from(view.querySelectorAll('.chat-error')).pop().textContent.trim()).toBe(
|
expect(Array.from(view.querySelectorAll('.chat-error')).pop().textContent.trim()).toBe(
|
||||||
"Error: couldn't find a groupchat participant based on your arguments");
|
"Error: couldn't find a groupchat participant based on your arguments");
|
||||||
|
@ -3154,7 +3153,7 @@ describe("Groupchats", function () {
|
||||||
// again via triggering Event doesn't work for some weird
|
// again via triggering Event doesn't work for some weird
|
||||||
// reason.
|
// reason.
|
||||||
textarea.value = '/owner annoyingGuy You\'re responsible';
|
textarea.value = '/owner annoyingGuy You\'re responsible';
|
||||||
bottom_panel.onFormSubmitted(new Event('submit'));
|
message_form.onFormSubmitted(new Event('submit'));
|
||||||
|
|
||||||
expect(view.model.validateRoleOrAffiliationChangeArgs.calls.count()).toBe(3);
|
expect(view.model.validateRoleOrAffiliationChangeArgs.calls.count()).toBe(3);
|
||||||
// Check that the member list now gets updated
|
// Check that the member list now gets updated
|
||||||
|
@ -3213,8 +3212,8 @@ describe("Groupchats", function () {
|
||||||
|
|
||||||
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
||||||
textarea.value = '/ban';
|
textarea.value = '/ban';
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13
|
keyCode: 13
|
||||||
|
@ -3232,7 +3231,7 @@ describe("Groupchats", function () {
|
||||||
// again via triggering Event doesn't work for some weird
|
// again via triggering Event doesn't work for some weird
|
||||||
// reason.
|
// reason.
|
||||||
textarea.value = '/ban annoyingGuy You\'re annoying';
|
textarea.value = '/ban annoyingGuy You\'re annoying';
|
||||||
bottom_panel.onFormSubmitted(new Event('submit'));
|
message_form.onFormSubmitted(new Event('submit'));
|
||||||
|
|
||||||
expect(view.model.validateRoleOrAffiliationChangeArgs.calls.count()).toBe(2);
|
expect(view.model.validateRoleOrAffiliationChangeArgs.calls.count()).toBe(2);
|
||||||
// Check that the member list now gets updated
|
// Check that the member list now gets updated
|
||||||
|
@ -3277,7 +3276,7 @@ describe("Groupchats", function () {
|
||||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||||
|
|
||||||
textarea.value = '/ban joe22';
|
textarea.value = '/ban joe22';
|
||||||
bottom_panel.onFormSubmitted(new Event('submit'));
|
message_form.onFormSubmitted(new Event('submit'));
|
||||||
await u.waitUntil(() => view.querySelector('converse-chat-message:last-child')?.textContent?.trim() ===
|
await u.waitUntil(() => view.querySelector('converse-chat-message:last-child')?.textContent?.trim() ===
|
||||||
"Error: couldn't find a groupchat participant based on your arguments");
|
"Error: couldn't find a groupchat participant based on your arguments");
|
||||||
done();
|
done();
|
||||||
|
@ -3313,8 +3312,8 @@ describe("Groupchats", function () {
|
||||||
|
|
||||||
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
||||||
textarea.value = '/kick';
|
textarea.value = '/kick';
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13
|
keyCode: 13
|
||||||
|
@ -3328,7 +3327,7 @@ describe("Groupchats", function () {
|
||||||
// again via triggering Event doesn't work for some weird
|
// again via triggering Event doesn't work for some weird
|
||||||
// reason.
|
// reason.
|
||||||
textarea.value = '/kick @annoying guy You\'re annoying';
|
textarea.value = '/kick @annoying guy You\'re annoying';
|
||||||
bottom_panel.onFormSubmitted(new Event('submit'));
|
message_form.onFormSubmitted(new Event('submit'));
|
||||||
|
|
||||||
expect(view.model.validateRoleOrAffiliationChangeArgs.calls.count()).toBe(2);
|
expect(view.model.validateRoleOrAffiliationChangeArgs.calls.count()).toBe(2);
|
||||||
expect(view.model.setRole).toHaveBeenCalled();
|
expect(view.model.setRole).toHaveBeenCalled();
|
||||||
|
@ -3415,8 +3414,8 @@ describe("Groupchats", function () {
|
||||||
|
|
||||||
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
||||||
textarea.value = '/op';
|
textarea.value = '/op';
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13
|
keyCode: 13
|
||||||
|
@ -3432,7 +3431,7 @@ describe("Groupchats", function () {
|
||||||
// again via triggering Event doesn't work for some weird
|
// again via triggering Event doesn't work for some weird
|
||||||
// reason.
|
// reason.
|
||||||
textarea.value = '/op trustworthyguy You\'re trustworthy';
|
textarea.value = '/op trustworthyguy You\'re trustworthy';
|
||||||
bottom_panel.onFormSubmitted(new Event('submit'));
|
message_form.onFormSubmitted(new Event('submit'));
|
||||||
|
|
||||||
expect(view.model.validateRoleOrAffiliationChangeArgs.calls.count()).toBe(2);
|
expect(view.model.validateRoleOrAffiliationChangeArgs.calls.count()).toBe(2);
|
||||||
expect(view.model.setRole).toHaveBeenCalled();
|
expect(view.model.setRole).toHaveBeenCalled();
|
||||||
|
@ -3476,7 +3475,7 @@ describe("Groupchats", function () {
|
||||||
// again via triggering Event doesn't work for some weird
|
// again via triggering Event doesn't work for some weird
|
||||||
// reason.
|
// reason.
|
||||||
textarea.value = '/deop trustworthyguy Perhaps not';
|
textarea.value = '/deop trustworthyguy Perhaps not';
|
||||||
bottom_panel.onFormSubmitted(new Event('submit'));
|
message_form.onFormSubmitted(new Event('submit'));
|
||||||
|
|
||||||
expect(view.model.validateRoleOrAffiliationChangeArgs.calls.count()).toBe(3);
|
expect(view.model.validateRoleOrAffiliationChangeArgs.calls.count()).toBe(3);
|
||||||
expect(view.model.setRole).toHaveBeenCalled();
|
expect(view.model.setRole).toHaveBeenCalled();
|
||||||
|
@ -3555,8 +3554,8 @@ describe("Groupchats", function () {
|
||||||
|
|
||||||
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
||||||
textarea.value = '/mute';
|
textarea.value = '/mute';
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13
|
keyCode: 13
|
||||||
|
@ -3571,7 +3570,7 @@ describe("Groupchats", function () {
|
||||||
// again via triggering Event doesn't work for some weird
|
// again via triggering Event doesn't work for some weird
|
||||||
// reason.
|
// reason.
|
||||||
textarea.value = '/mute annoyingGuy You\'re annoying';
|
textarea.value = '/mute annoyingGuy You\'re annoying';
|
||||||
bottom_panel.onFormSubmitted(new Event('submit'));
|
message_form.onFormSubmitted(new Event('submit'));
|
||||||
|
|
||||||
expect(view.model.validateRoleOrAffiliationChangeArgs.calls.count()).toBe(2);
|
expect(view.model.validateRoleOrAffiliationChangeArgs.calls.count()).toBe(2);
|
||||||
expect(view.model.setRole).toHaveBeenCalled();
|
expect(view.model.setRole).toHaveBeenCalled();
|
||||||
|
@ -3612,7 +3611,7 @@ describe("Groupchats", function () {
|
||||||
// again via triggering Event doesn't work for some weird
|
// again via triggering Event doesn't work for some weird
|
||||||
// reason.
|
// reason.
|
||||||
textarea.value = '/voice annoyingGuy Now you can talk again';
|
textarea.value = '/voice annoyingGuy Now you can talk again';
|
||||||
bottom_panel.onFormSubmitted(new Event('submit'));
|
message_form.onFormSubmitted(new Event('submit'));
|
||||||
|
|
||||||
expect(view.model.validateRoleOrAffiliationChangeArgs.calls.count()).toBe(3);
|
expect(view.model.validateRoleOrAffiliationChangeArgs.calls.count()).toBe(3);
|
||||||
expect(view.model.setRole).toHaveBeenCalled();
|
expect(view.model.setRole).toHaveBeenCalled();
|
||||||
|
@ -3660,8 +3659,8 @@ describe("Groupchats", function () {
|
||||||
spyOn(_converse.api, 'confirm').and.callThrough();
|
spyOn(_converse.api, 'confirm').and.callThrough();
|
||||||
let textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
let textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
||||||
textarea.value = '/destroy';
|
textarea.value = '/destroy';
|
||||||
let bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
let message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onFormSubmitted(new Event('submit'));
|
message_form.onFormSubmitted(new Event('submit'));
|
||||||
let modal = await u.waitUntil(() => document.querySelector('.modal-dialog'));
|
let modal = await u.waitUntil(() => document.querySelector('.modal-dialog'));
|
||||||
await u.waitUntil(() => u.isVisible(modal));
|
await u.waitUntil(() => u.isVisible(modal));
|
||||||
|
|
||||||
|
@ -3711,8 +3710,8 @@ describe("Groupchats", function () {
|
||||||
view = _converse.api.chatviews.get(new_muc_jid);
|
view = _converse.api.chatviews.get(new_muc_jid);
|
||||||
textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
||||||
textarea.value = '/destroy';
|
textarea.value = '/destroy';
|
||||||
bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onFormSubmitted(new Event('submit'));
|
message_form.onFormSubmitted(new Event('submit'));
|
||||||
modal = await u.waitUntil(() => document.querySelector('.modal-dialog'));
|
modal = await u.waitUntil(() => document.querySelector('.modal-dialog'));
|
||||||
await u.waitUntil(() => u.isVisible(modal));
|
await u.waitUntil(() => u.isVisible(modal));
|
||||||
|
|
||||||
|
@ -4988,8 +4987,8 @@ describe("Groupchats", function () {
|
||||||
const view = _converse.api.chatviews.get(muc_jid);
|
const view = _converse.api.chatviews.get(muc_jid);
|
||||||
const textarea = await u.waitUntil(() => view.querySelector('textarea.chat-textarea'));
|
const textarea = await u.waitUntil(() => view.querySelector('textarea.chat-textarea'));
|
||||||
textarea.value = 'Hello world';
|
textarea.value = 'Hello world';
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onFormSubmitted(new Event('submit'));
|
message_form.onFormSubmitted(new Event('submit'));
|
||||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||||
|
|
||||||
let stanza = u.toStanza(`
|
let stanza = u.toStanza(`
|
||||||
|
@ -5006,7 +5005,7 @@ describe("Groupchats", function () {
|
||||||
"Your message was not delivered because you weren't allowed to send it.");
|
"Your message was not delivered because you weren't allowed to send it.");
|
||||||
|
|
||||||
textarea.value = 'Hello again';
|
textarea.value = 'Hello again';
|
||||||
bottom_panel.onFormSubmitted(new Event('submit'));
|
message_form.onFormSubmitted(new Event('submit'));
|
||||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 2);
|
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 2);
|
||||||
|
|
||||||
stanza = u.toStanza(`
|
stanza = u.toStanza(`
|
||||||
|
|
|
@ -79,7 +79,6 @@ describe("Notifications", function () {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it("is shown for headline messages", mock.initConverse([], {}, async (done, _converse) => {
|
it("is shown for headline messages", mock.initConverse([], {}, async (done, _converse) => {
|
||||||
|
|
||||||
const stub = jasmine.createSpyObj('MyNotification', ['onclick', 'close']);
|
const stub = jasmine.createSpyObj('MyNotification', ['onclick', 'close']);
|
||||||
spyOn(window, 'Notification').and.returnValue(stub);
|
spyOn(window, 'Notification').and.returnValue(stub);
|
||||||
|
|
||||||
|
|
|
@ -112,8 +112,8 @@ describe("The OMEMO module", function() {
|
||||||
|
|
||||||
const textarea = view.querySelector('.chat-textarea');
|
const textarea = view.querySelector('.chat-textarea');
|
||||||
textarea.value = 'This message will be encrypted';
|
textarea.value = 'This message will be encrypted';
|
||||||
const bottom_panel = view.querySelector('converse-chat-bottom-panel');
|
const message_form = view.querySelector('converse-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
|
@ -294,8 +294,8 @@ describe("The OMEMO module", function() {
|
||||||
|
|
||||||
const textarea = view.querySelector('.chat-textarea');
|
const textarea = view.querySelector('.chat-textarea');
|
||||||
textarea.value = 'This message will be encrypted';
|
textarea.value = 'This message will be encrypted';
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
|
@ -459,8 +459,8 @@ describe("The OMEMO module", function() {
|
||||||
|
|
||||||
const textarea = view.querySelector('.chat-textarea');
|
const textarea = view.querySelector('.chat-textarea');
|
||||||
textarea.value = 'This is an encrypted message from this device';
|
textarea.value = 'This is an encrypted message from this device';
|
||||||
const bottom_panel = view.querySelector('converse-chat-bottom-panel');
|
const message_form = view.querySelector('converse-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
|
@ -515,8 +515,8 @@ describe("The OMEMO module", function() {
|
||||||
|
|
||||||
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
const textarea = await u.waitUntil(() => view.querySelector('.chat-textarea'));
|
||||||
textarea.value = 'This message will be encrypted';
|
textarea.value = 'This message will be encrypted';
|
||||||
const bottom_panel = view.querySelector('converse-muc-bottom-panel');
|
const message_form = view.querySelector('converse-muc-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13 // Enter
|
keyCode: 13 // Enter
|
||||||
|
@ -1232,8 +1232,8 @@ describe("The OMEMO module", function() {
|
||||||
|
|
||||||
const textarea = view.querySelector('.chat-textarea');
|
const textarea = view.querySelector('.chat-textarea');
|
||||||
textarea.value = 'This message will be sent encrypted';
|
textarea.value = 'This message will be sent encrypted';
|
||||||
const bottom_panel = view.querySelector('converse-chat-bottom-panel');
|
const message_form = view.querySelector('converse-message-form');
|
||||||
bottom_panel.onKeyDown({
|
message_form.onKeyDown({
|
||||||
target: textarea,
|
target: textarea,
|
||||||
preventDefault: function preventDefault () {},
|
preventDefault: function preventDefault () {},
|
||||||
keyCode: 13
|
keyCode: 13
|
||||||
|
|
|
@ -89,6 +89,14 @@ export default class BaseChatView extends ElementView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getMessageForm () {
|
||||||
|
if (this.model.get('type') === _converse.CHATROOMS_TYPE) {
|
||||||
|
return this.querySelector('converse-muc-message-form');
|
||||||
|
} else {
|
||||||
|
return this.querySelector('converse-message-form');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scrolls the chat down.
|
* Scrolls the chat down.
|
||||||
*
|
*
|
||||||
|
@ -107,7 +115,7 @@ export default class BaseChatView extends ElementView {
|
||||||
|
|
||||||
onWindowStateChanged (data) {
|
onWindowStateChanged (data) {
|
||||||
if (data.state === 'visible') {
|
if (data.state === 'visible') {
|
||||||
if (!this.model.isHidden() && this.model.get('num_unread', 0)) {
|
if (!this.model.isHidden()) {
|
||||||
this.model.clearUnreadMsgCounter();
|
this.model.clearUnreadMsgCounter();
|
||||||
}
|
}
|
||||||
} else if (data.state === 'hidden') {
|
} else if (data.state === 'hidden') {
|
||||||
|
|
|
@ -48,7 +48,7 @@ export default class ChatContent extends CustomElement {
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
return html`
|
return html`
|
||||||
${ this.model.ui.get('chat-content-spinner-top') ? html`<span class="spinner fa fa-spinner centered"></span>` : '' }
|
${ this.model.ui?.get('chat-content-spinner-top') ? html`<span class="spinner fa fa-spinner centered"></span>` : '' }
|
||||||
<converse-message-history
|
<converse-message-history
|
||||||
.model=${this.model}
|
.model=${this.model}
|
||||||
.observer=${this.observer}
|
.observer=${this.observer}
|
||||||
|
@ -105,7 +105,7 @@ export default class ChatContent extends CustomElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
setAnchoredMessage (entries) {
|
setAnchoredMessage (entries) {
|
||||||
if (this.model.ui.get('chat-content-spinner-top')) {
|
if (!this.model?.ui || this.model.ui.get('chat-content-spinner-top')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
entries = entries.filter(e => e.isIntersecting);
|
entries = entries.filter(e => e.isIntersecting);
|
||||||
|
|
|
@ -153,7 +153,7 @@ export default class EmojiPicker extends CustomElement {
|
||||||
insertIntoTextArea (value) {
|
insertIntoTextArea (value) {
|
||||||
const autocompleting = this.model.get('autocompleting');
|
const autocompleting = this.model.get('autocompleting');
|
||||||
const ac_position = this.model.get('ac_position');
|
const ac_position = this.model.get('ac_position');
|
||||||
this.chatview.getBottomPanel().insertIntoTextArea(value, autocompleting, false, ac_position);
|
this.chatview.getMessageForm().insertIntoTextArea(value, autocompleting, false, ac_position);
|
||||||
this.model.set({'autocompleting': null, 'query': '', 'ac_position': null});
|
this.model.set({'autocompleting': null, 'query': '', 'ac_position': null});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
26
src/shared/chat/message-limit.js
Normal file
26
src/shared/chat/message-limit.js
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import tpl_message_limit from './templates/message-limit.js';
|
||||||
|
import { CustomElement } from 'shared/components/element.js';
|
||||||
|
import { api } from '@converse/headless/core';
|
||||||
|
|
||||||
|
export default class MessageLimitIndicator extends CustomElement {
|
||||||
|
|
||||||
|
static get properties () {
|
||||||
|
return {
|
||||||
|
model: { type: Object }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback () {
|
||||||
|
super.connectedCallback();
|
||||||
|
this.listenTo(this.model, 'change:draft', this.requestUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const limit = api.settings.get('message_limit');
|
||||||
|
if (!limit) return '';
|
||||||
|
const chars = this.model.get('draft') || '';
|
||||||
|
return tpl_message_limit(limit - chars.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
api.elements.define('converse-message-limit-indicator', MessageLimitIndicator);
|
7
src/shared/chat/templates/message-limit.js
Normal file
7
src/shared/chat/templates/message-limit.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import { __ } from 'i18n';
|
||||||
|
import { html } from 'lit';
|
||||||
|
|
||||||
|
export default (counter) => {
|
||||||
|
const i18n_chars_remaining = __('Message characters remaining');
|
||||||
|
return html`<span class="message-limit ${counter < 1 ? 'error' : ''}" title="${i18n_chars_remaining}">${counter}</span>`;
|
||||||
|
}
|
|
@ -1,7 +1,8 @@
|
||||||
import "./emoji-picker.js";
|
import './emoji-picker.js';
|
||||||
|
import 'shared/chat/message-limit.js';
|
||||||
import { CustomElement } from 'shared/components/element.js';
|
import { CustomElement } from 'shared/components/element.js';
|
||||||
import { __ } from 'i18n';
|
import { __ } from 'i18n';
|
||||||
import { _converse, api, converse } from "@converse/headless/core";
|
import { _converse, api, converse } from '@converse/headless/core';
|
||||||
import { html } from 'lit';
|
import { html } from 'lit';
|
||||||
import { until } from 'lit/directives/until.js';
|
import { until } from 'lit/directives/until.js';
|
||||||
|
|
||||||
|
@ -14,7 +15,6 @@ export class ChatToolbar extends CustomElement {
|
||||||
|
|
||||||
static get properties () {
|
static get properties () {
|
||||||
return {
|
return {
|
||||||
chatview: { type: Object }, // Used by getToolbarButtons hooks
|
|
||||||
composing_spoiler: { type: Boolean },
|
composing_spoiler: { type: Boolean },
|
||||||
hidden_occupants: { type: Boolean },
|
hidden_occupants: { type: Boolean },
|
||||||
is_groupchat: { type: Boolean },
|
is_groupchat: { type: Boolean },
|
||||||
|
@ -25,23 +25,38 @@ export class ChatToolbar extends CustomElement {
|
||||||
show_occupants_toggle: { type: Boolean },
|
show_occupants_toggle: { type: Boolean },
|
||||||
show_send_button: { type: Boolean },
|
show_send_button: { type: Boolean },
|
||||||
show_spoiler_button: { type: Boolean },
|
show_spoiler_button: { type: Boolean },
|
||||||
show_toolbar: { type: Boolean }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
connectedCallback () {
|
||||||
|
super.connectedCallback();
|
||||||
|
this.listenTo(this.model, 'change:composing_spoiler', this.requestUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const i18n_send_message = __('Send the message');
|
const i18n_send_message = __('Send the message');
|
||||||
return html`
|
return html`
|
||||||
${ this.show_toolbar ? html`<span class="toolbar-buttons">${until(this.getButtons(), '')}</span>` : '' }
|
<span class="toolbar-buttons">${until(this.getButtons(), '')}</span>
|
||||||
${ this.show_send_button ? html`<button type="submit" class="btn send-button fa fa-paper-plane" title="${ i18n_send_message }"></button>` : '' }
|
${ this.show_send_button ? html`<button type="submit" class="btn send-button fa fa-paper-plane" title="${ i18n_send_message }"></button>` : '' }
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
firstUpdated () {
|
||||||
|
/**
|
||||||
|
* Triggered once the _converse.ChatBoxView's toolbar has been rendered
|
||||||
|
* @event _converse#renderToolbar
|
||||||
|
* @type { _converse.ChatBoxView }
|
||||||
|
* @example _converse.api.listen.on('renderToolbar', this => { ... });
|
||||||
|
*/
|
||||||
|
api.trigger('renderToolbar', this);
|
||||||
|
}
|
||||||
|
|
||||||
getButtons () {
|
getButtons () {
|
||||||
const buttons = [];
|
const buttons = [];
|
||||||
|
|
||||||
if (this.show_emoji_button) {
|
if (this.show_emoji_button) {
|
||||||
buttons.push(html`<converse-emoji-dropdown .chatview=${this.chatview}></converse-dropdown>`);
|
const chatview = _converse.chatboxviews.get(this.model.get('jid'));
|
||||||
|
buttons.push(html`<converse-emoji-dropdown .chatview=${chatview}></converse-dropdown>`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.show_call_button) {
|
if (this.show_call_button) {
|
||||||
|
@ -52,10 +67,13 @@ export class ChatToolbar extends CustomElement {
|
||||||
</button>`
|
</button>`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const i18n_chars_remaining = __('Message characters remaining');
|
|
||||||
const message_limit = api.settings.get('message_limit');
|
const message_limit = api.settings.get('message_limit');
|
||||||
if (message_limit) {
|
if (message_limit) {
|
||||||
buttons.push(html`<span class="right message-limit" title="${i18n_chars_remaining}">${this.message_limit}</span>`);
|
buttons.push(html`
|
||||||
|
<converse-message-limit-indicator .model=${this.model} class="right">
|
||||||
|
</converse-message-limit-indicator>`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.show_spoiler_button) {
|
if (this.show_spoiler_button) {
|
||||||
|
@ -109,7 +127,7 @@ export class ChatToolbar extends CustomElement {
|
||||||
|
|
||||||
getSpoilerButton () {
|
getSpoilerButton () {
|
||||||
const model = this.model;
|
const model = this.model;
|
||||||
if (!this.is_groupchat && model.presence.resources.length === 0) {
|
if (!this.is_groupchat && !model.presence?.resources.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
import { _converse, api } from '@converse/headless/core';
|
import { _converse, api } from '@converse/headless/core';
|
||||||
|
|
||||||
export function onScrolledDown (model) {
|
export function onScrolledDown (model) {
|
||||||
if (!model.isHidden()) {
|
if (!model.isHidden()) {
|
||||||
model.clearUnreadMsgCounter();
|
if (api.settings.get('allow_url_history_change')) {
|
||||||
if (api.settings.get('allow_url_history_change')) {
|
// Clear location hash if set to one of the messages in our history
|
||||||
// Clear location hash if set to one of the messages in our history
|
const hash = window.location.hash;
|
||||||
const hash = window.location.hash;
|
hash && model.messages.get(hash.slice(1)) && _converse.router.history.navigate();
|
||||||
hash && model.messages.get(hash.slice(1)) && _converse.router.history.navigate();
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user