Move more methods from ChatBoxView to shared base class
This commit is contained in:
parent
bb317d1abb
commit
b8d710800a
|
@ -914,6 +914,7 @@ const ChatBox = ModelWithContact.extend({
|
|||
return;
|
||||
} else {
|
||||
u.safeSave(this, {'hidden': false});
|
||||
this.trigger('show');
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
|
|
@ -3,11 +3,9 @@ import UserDetailsModal from 'modals/user-details.js';
|
|||
import log from '@converse/headless/log';
|
||||
import tpl_chatbox from 'templates/chatbox.js';
|
||||
import tpl_chatbox_head from 'templates/chatbox_head.js';
|
||||
import tpl_spinner from 'templates/spinner.js';
|
||||
import { __ } from 'i18n';
|
||||
import { _converse, api, converse } from '@converse/headless/core';
|
||||
import { debounce } from 'lodash-es';
|
||||
import { html, render } from 'lit-html';
|
||||
import { render } from 'lit-html';
|
||||
|
||||
const u = converse.env.utils;
|
||||
const { dayjs } = converse.env;
|
||||
|
@ -71,8 +69,7 @@ export default class ChatView extends BaseChatView {
|
|||
this.listenTo(this.model, 'change:show_help_messages', this.renderHelpMessages);
|
||||
|
||||
await this.model.messages.fetched;
|
||||
this.model.maybeShow();
|
||||
this.scrollDown();
|
||||
!this.model.get('hidden') && this.afterShown()
|
||||
/**
|
||||
* Triggered once the {@link _converse.ChatBoxView} has been initialized
|
||||
* @event _converse#chatBoxViewInitialized
|
||||
|
@ -82,21 +79,6 @@ export default class ChatView extends BaseChatView {
|
|||
api.trigger('chatBoxViewInitialized', this);
|
||||
}
|
||||
|
||||
initDebounced () {
|
||||
this.markScrolled = debounce(this._markScrolled, 100);
|
||||
this.debouncedScrollDown = debounce(this.scrollDown, 100);
|
||||
|
||||
// For tests that use Jasmine.Clock we want to turn of
|
||||
// debouncing, since setTimeout breaks.
|
||||
if (api.settings.get('debounced_content_rendering')) {
|
||||
this.renderChatHistory = debounce(() => this.renderChatContent(false), 100);
|
||||
this.renderNotifications = debounce(() => this.renderChatContent(true), 100);
|
||||
} else {
|
||||
this.renderChatHistory = () => this.renderChatContent(false);
|
||||
this.renderNotifications = () => this.renderChatContent(true);
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const result = tpl_chatbox(Object.assign(this.model.toJSON(), { 'markScrolled': ev => this.markScrolled(ev) }));
|
||||
render(result, this);
|
||||
|
@ -110,22 +92,6 @@ export default class ChatView extends BaseChatView {
|
|||
return this;
|
||||
}
|
||||
|
||||
onMessageAdded (message) {
|
||||
this.renderChatHistory();
|
||||
|
||||
if (u.isNewMessage(message)) {
|
||||
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.model.get('scrolled', true)) {
|
||||
this.showNewMessagesIndicator();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getNotifications () {
|
||||
if (this.model.notifications.get('chat_state') === _converse.COMPOSING) {
|
||||
return __('%1$s is typing', this.model.getDisplayName());
|
||||
|
@ -147,22 +113,6 @@ export default class ChatView extends BaseChatView {
|
|||
];
|
||||
}
|
||||
|
||||
renderHelpMessages () {
|
||||
render(
|
||||
html`
|
||||
<converse-chat-help
|
||||
.model=${this.model}
|
||||
.messages=${this.getHelpMessages()}
|
||||
?hidden=${!this.model.get('show_help_messages')}
|
||||
type="info"
|
||||
chat_type="${this.model.get('type')}"
|
||||
></converse-chat-help>
|
||||
`,
|
||||
|
||||
this.help_container
|
||||
);
|
||||
}
|
||||
|
||||
showControlBox () {
|
||||
// Used in mobile view, to navigate back to the controlbox
|
||||
_converse.chatboxviews.get('controlbox')?.show();
|
||||
|
@ -285,51 +235,6 @@ export default class ChatView extends BaseChatView {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scroll to the previously saved scrollTop position, or scroll
|
||||
* down if it wasn't set.
|
||||
*/
|
||||
maintainScrollTop () {
|
||||
const pos = this.model.get('scrollTop');
|
||||
if (pos) {
|
||||
this.msgs_container.scrollTop = pos;
|
||||
} else {
|
||||
this.scrollDown();
|
||||
}
|
||||
}
|
||||
|
||||
addSpinner (append = false) {
|
||||
if (this.querySelector('.spinner') === null) {
|
||||
const el = u.getElementFromTemplateResult(tpl_spinner());
|
||||
if (append) {
|
||||
this.content.insertAdjacentElement('beforeend', el);
|
||||
this.scrollDown();
|
||||
} else {
|
||||
this.content.insertAdjacentElement('afterbegin', el);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clearSpinner () {
|
||||
this.content.querySelectorAll('.spinner').forEach(u.removeElement);
|
||||
}
|
||||
|
||||
onStatusMessageChanged (item) {
|
||||
this.renderHeading();
|
||||
/**
|
||||
* When a contact's custom status message has changed.
|
||||
* @event _converse#contactStatusMessageChanged
|
||||
* @type {object}
|
||||
* @property { object } contact - The chat buddy
|
||||
* @property { string } message - The message text
|
||||
* @example _converse.api.listen.on('contactStatusMessageChanged', obj => { ... });
|
||||
*/
|
||||
api.trigger('contactStatusMessageChanged', {
|
||||
'contact': item.attributes,
|
||||
'message': item.get('status')
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a message element, determine wether it should be
|
||||
* marked as a followup message to the previous element.
|
||||
|
@ -472,10 +377,6 @@ export default class ChatView extends BaseChatView {
|
|||
}
|
||||
}
|
||||
|
||||
getOwnMessages () {
|
||||
return this.model.messages.filter({ 'sender': 'me' });
|
||||
}
|
||||
|
||||
onEscapePressed (ev) {
|
||||
ev.preventDefault();
|
||||
const idx = this.model.messages.findLastIndex('correcting');
|
||||
|
@ -506,72 +407,6 @@ export default class ChatView extends BaseChatView {
|
|||
}
|
||||
}
|
||||
|
||||
onMessageEditButtonClicked (message) {
|
||||
const currently_correcting = this.model.messages.findWhere('correcting');
|
||||
const unsent_text = this.querySelector('.chat-textarea')?.value;
|
||||
if (unsent_text && (!currently_correcting || currently_correcting.get('message') !== unsent_text)) {
|
||||
if (!confirm(__('You have an unsent message which will be lost if you continue. Are you sure?'))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (currently_correcting !== message) {
|
||||
currently_correcting?.save('correcting', false);
|
||||
message.save('correcting', true);
|
||||
this.insertIntoTextArea(u.prefixMentions(message), true, true);
|
||||
} else {
|
||||
message.save('correcting', false);
|
||||
this.insertIntoTextArea('', true, false);
|
||||
}
|
||||
}
|
||||
|
||||
editLaterMessage () {
|
||||
let message;
|
||||
let idx = this.model.messages.findLastIndex('correcting');
|
||||
if (idx >= 0) {
|
||||
this.model.messages.at(idx).save('correcting', false);
|
||||
while (idx < this.model.messages.length - 1) {
|
||||
idx += 1;
|
||||
const candidate = this.model.messages.at(idx);
|
||||
if (candidate.get('editable')) {
|
||||
message = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (message) {
|
||||
this.insertIntoTextArea(u.prefixMentions(message), true, true);
|
||||
message.save('correcting', true);
|
||||
} else {
|
||||
this.insertIntoTextArea('', true, false);
|
||||
}
|
||||
}
|
||||
|
||||
editEarlierMessage () {
|
||||
let message;
|
||||
let idx = this.model.messages.findLastIndex('correcting');
|
||||
if (idx >= 0) {
|
||||
this.model.messages.at(idx).save('correcting', false);
|
||||
while (idx > 0) {
|
||||
idx -= 1;
|
||||
const candidate = this.model.messages.at(idx);
|
||||
if (candidate.get('editable')) {
|
||||
message = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
message =
|
||||
message ||
|
||||
this.getOwnMessages()
|
||||
.reverse()
|
||||
.find(m => m.get('editable'));
|
||||
if (message) {
|
||||
this.insertIntoTextArea(u.prefixMentions(message), true, true);
|
||||
message.save('correcting', true);
|
||||
}
|
||||
}
|
||||
|
||||
inputChanged (ev) { // eslint-disable-line class-methods-use-this
|
||||
const height = ev.target.scrollHeight + 'px';
|
||||
if (ev.target.style.height != height) {
|
||||
|
@ -580,17 +415,6 @@ export default class ChatView extends BaseChatView {
|
|||
}
|
||||
}
|
||||
|
||||
async clearMessages (ev) {
|
||||
if (ev && ev.preventDefault) {
|
||||
ev.preventDefault();
|
||||
}
|
||||
const result = confirm(__('Are you sure you want to clear the messages from this conversation?'));
|
||||
if (result === true) {
|
||||
await this.model.clearMessages();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
onPresenceChanged (item) {
|
||||
const show = item.get('show');
|
||||
const fullname = this.model.getDisplayName();
|
||||
|
@ -639,10 +463,6 @@ export default class ChatView extends BaseChatView {
|
|||
this.maybeFocus();
|
||||
}
|
||||
|
||||
showNewMessagesIndicator () {
|
||||
u.showElement(this.querySelector('.new-msgs-indicator'));
|
||||
}
|
||||
|
||||
viewUnreadMessages () {
|
||||
this.model.save({ 'scrolled': false, 'scrollTop': null });
|
||||
this.scrollDown();
|
||||
|
|
|
@ -67,10 +67,8 @@ class ControlBoxView extends ElementView {
|
|||
}
|
||||
}
|
||||
|
||||
async close (ev) {
|
||||
if (ev && ev.preventDefault) {
|
||||
ev.preventDefault();
|
||||
}
|
||||
close (ev) {
|
||||
ev?.preventDefault?.();
|
||||
if (
|
||||
ev?.name === 'closeAllChatBoxes' &&
|
||||
(_converse.disconnection_cause !== _converse.LOGOUT ||
|
||||
|
@ -81,30 +79,11 @@ class ControlBoxView extends ElementView {
|
|||
if (api.settings.get('sticky_controlbox')) {
|
||||
return;
|
||||
}
|
||||
const connection = _converse?.connection || {};
|
||||
if (connection.connected && !connection.disconnecting) {
|
||||
await new Promise((resolve, reject) => {
|
||||
return this.model.save(
|
||||
{ 'closed': true },
|
||||
{ 'success': resolve, 'error': reject, 'wait': true }
|
||||
);
|
||||
});
|
||||
} else {
|
||||
this.model.trigger('hide');
|
||||
}
|
||||
u.safeSave(this.model, { 'closed': true });
|
||||
api.trigger('controlBoxClosed', this);
|
||||
return this;
|
||||
}
|
||||
|
||||
hide () {
|
||||
if (api.settings.get('sticky_controlbox')) {
|
||||
return;
|
||||
}
|
||||
u.addClass('hidden', this);
|
||||
api.trigger('chatBoxClosed', this);
|
||||
return this;
|
||||
}
|
||||
|
||||
show () {
|
||||
this.model.set('closed', false);
|
||||
this.classList.remove('hidden');
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import debounce from 'lodash/debounce';
|
||||
import log from '@converse/headless/log';
|
||||
import tpl_chatbox_message_form from 'templates/chatbox_message_form.js';
|
||||
import tpl_spinner from 'templates/spinner.js';
|
||||
import tpl_toolbar from 'templates/toolbar.js';
|
||||
import { ElementView } from '@converse/skeletor/src/element.js';
|
||||
import { __ } from 'i18n';
|
||||
import { _converse, api, converse } from '@converse/headless/core';
|
||||
import { debounce } from 'lodash-es';
|
||||
import { html, render } from 'lit-html';
|
||||
|
||||
const u = converse.env.utils;
|
||||
|
@ -45,6 +46,21 @@ export default class BaseChatView extends ElementView {
|
|||
render(this.tpl_chat_content({ messages, 'notifications': this.getNotifications() }), this.msgs_container);
|
||||
}
|
||||
|
||||
renderHelpMessages () {
|
||||
render(
|
||||
html`
|
||||
<converse-chat-help
|
||||
.model=${this.model}
|
||||
.messages=${this.getHelpMessages()}
|
||||
?hidden=${!this.model.get('show_help_messages')}
|
||||
type="info"
|
||||
chat_type="${this.model.get('type')}"
|
||||
></converse-chat-help>
|
||||
`,
|
||||
this.help_container
|
||||
);
|
||||
}
|
||||
|
||||
renderMessageForm () {
|
||||
const form_container = this.querySelector('.message-form-container');
|
||||
render(
|
||||
|
@ -160,6 +176,114 @@ export default class BaseChatView extends ElementView {
|
|||
api.trigger('chatBoxFocused', this, ev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scroll to the previously saved scrollTop position, or scroll
|
||||
* down if it wasn't set.
|
||||
*/
|
||||
maintainScrollTop () {
|
||||
const pos = this.model.get('scrollTop');
|
||||
if (pos) {
|
||||
this.msgs_container.scrollTop = pos;
|
||||
} else {
|
||||
this.scrollDown();
|
||||
}
|
||||
}
|
||||
|
||||
addSpinner (append = false) {
|
||||
if (this.querySelector('.spinner') === null) {
|
||||
const el = u.getElementFromTemplateResult(tpl_spinner());
|
||||
if (append) {
|
||||
this.content.insertAdjacentElement('beforeend', el);
|
||||
this.scrollDown();
|
||||
} else {
|
||||
this.content.insertAdjacentElement('afterbegin', el);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clearSpinner () {
|
||||
this.content.querySelectorAll('.spinner').forEach(u.removeElement);
|
||||
}
|
||||
|
||||
onStatusMessageChanged (item) {
|
||||
this.renderHeading();
|
||||
/**
|
||||
* When a contact's custom status message has changed.
|
||||
* @event _converse#contactStatusMessageChanged
|
||||
* @type {object}
|
||||
* @property { object } contact - The chat buddy
|
||||
* @property { string } message - The message text
|
||||
* @example _converse.api.listen.on('contactStatusMessageChanged', obj => { ... });
|
||||
*/
|
||||
api.trigger('contactStatusMessageChanged', {
|
||||
'contact': item.attributes,
|
||||
'message': item.get('status')
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
getOwnMessages () {
|
||||
return this.model.messages.filter({ 'sender': 'me' });
|
||||
}
|
||||
|
||||
async clearMessages (ev) {
|
||||
if (ev && ev.preventDefault) {
|
||||
ev.preventDefault();
|
||||
}
|
||||
const result = confirm(__('Are you sure you want to clear the messages from this conversation?'));
|
||||
if (result === true) {
|
||||
await this.model.clearMessages();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
editEarlierMessage () {
|
||||
let message;
|
||||
let idx = this.model.messages.findLastIndex('correcting');
|
||||
if (idx >= 0) {
|
||||
this.model.messages.at(idx).save('correcting', false);
|
||||
while (idx > 0) {
|
||||
idx -= 1;
|
||||
const candidate = this.model.messages.at(idx);
|
||||
if (candidate.get('editable')) {
|
||||
message = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
message =
|
||||
message ||
|
||||
this.getOwnMessages()
|
||||
.reverse()
|
||||
.find(m => m.get('editable'));
|
||||
if (message) {
|
||||
this.insertIntoTextArea(u.prefixMentions(message), true, true);
|
||||
message.save('correcting', true);
|
||||
}
|
||||
}
|
||||
|
||||
editLaterMessage () {
|
||||
let message;
|
||||
let idx = this.model.messages.findLastIndex('correcting');
|
||||
if (idx >= 0) {
|
||||
this.model.messages.at(idx).save('correcting', false);
|
||||
while (idx < this.model.messages.length - 1) {
|
||||
idx += 1;
|
||||
const candidate = this.model.messages.at(idx);
|
||||
if (candidate.get('editable')) {
|
||||
message = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (message) {
|
||||
this.insertIntoTextArea(u.prefixMentions(message), true, true);
|
||||
message.save('correcting', true);
|
||||
} else {
|
||||
this.insertIntoTextArea('', true, false);
|
||||
}
|
||||
}
|
||||
|
||||
async getHeadingDropdownItem (promise_or_data) { // eslint-disable-line class-methods-use-this
|
||||
const data = await promise_or_data;
|
||||
return html`
|
||||
|
@ -183,6 +307,26 @@ export default class BaseChatView extends ElementView {
|
|||
}
|
||||
}
|
||||
|
||||
showNewMessagesIndicator () {
|
||||
u.showElement(this.querySelector('.new-msgs-indicator'));
|
||||
}
|
||||
|
||||
onMessageAdded (message) {
|
||||
this.renderChatHistory();
|
||||
|
||||
if (u.isNewMessage(message)) {
|
||||
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.model.get('scrolled', true)) {
|
||||
this.showNewMessagesIndicator();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onEmojiReceivedFromPicker (emoji) {
|
||||
const model = this.querySelector('converse-emoji-picker').model;
|
||||
const autocompleting = model.get('autocompleting');
|
||||
|
@ -190,6 +334,24 @@ export default class BaseChatView extends ElementView {
|
|||
this.insertIntoTextArea(emoji, autocompleting, false, ac_position);
|
||||
}
|
||||
|
||||
onMessageEditButtonClicked (message) {
|
||||
const currently_correcting = this.model.messages.findWhere('correcting');
|
||||
const unsent_text = this.querySelector('.chat-textarea')?.value;
|
||||
if (unsent_text && (!currently_correcting || currently_correcting.get('message') !== unsent_text)) {
|
||||
if (!confirm(__('You have an unsent message which will be lost if you continue. Are you sure?'))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (currently_correcting !== message) {
|
||||
currently_correcting?.save('correcting', false);
|
||||
message.save('correcting', true);
|
||||
this.insertIntoTextArea(u.prefixMentions(message), true, true);
|
||||
} else {
|
||||
message.save('correcting', false);
|
||||
this.insertIntoTextArea('', true, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a particular string value into the textarea of this chat box.
|
||||
* @private
|
||||
|
|
|
@ -13,6 +13,7 @@ export default (o) => html`
|
|||
<div class="suggestion-box">
|
||||
<ul class="suggestion-box__results suggestion-box__results--above" hidden=""></ul>
|
||||
<textarea
|
||||
autofocus
|
||||
type="text"
|
||||
class="chat-textarea suggestion-box__input
|
||||
${ o.show_send_button ? 'chat-textarea-send-button' : '' }
|
||||
|
|
Loading…
Reference in New Issue
Block a user