diff --git a/spec/corrections.js b/spec/corrections.js index ca676168a..5375549cc 100644 --- a/spec/corrections.js +++ b/spec/corrections.js @@ -146,6 +146,9 @@ describe("A Chat Message", function () { keyCode: 13 // Enter }); await u.waitUntil(() => textarea.value === ''); + await u.waitUntil(() => Array.from(view.querySelectorAll('.chat-msg__text')).filter( + m => m.textContent === 'It is the east, and Juliet is the sun.').length); + const messages = view.querySelectorAll('.chat-msg'); expect(messages.length).toBe(3); expect(messages[0].querySelector('.chat-msg__text').textContent) @@ -244,9 +247,9 @@ describe("A Chat Message", function () { action = view.querySelector('.chat-msg .chat-msg__action'); action.style.opacity = 1; action.click(); - expect(textarea.value).toBe(''); expect(view.model.messages.at(0).get('correcting')).toBe(false); expect(view.querySelectorAll('.chat-msg').length).toBe(1); + expect(textarea.value).toBe(''); await u.waitUntil(() => (u.hasClass('correcting', view.querySelector('.chat-msg')) === false), 500); // Test that messages from other users don't have the pencil icon diff --git a/src/components/chat_content.js b/src/components/chat_content.js index 527811abf..9ef6a789a 100644 --- a/src/components/chat_content.js +++ b/src/components/chat_content.js @@ -1,41 +1,56 @@ import "./message-history"; -import xss from "xss/dist/xss"; import { CustomElement } from './element.js'; +import { _converse, api } from "@converse/headless/core"; import { html } from 'lit-element'; -import { unsafeHTML } from 'lit-html/directives/unsafe-html.js'; -import { api } from "@converse/headless/core"; export default class ChatContent extends CustomElement { static get properties () { return { - chatview: { type: Object} + jid: { type: String } } } connectedCallback () { super.connectedCallback(); - const model = this.chatview.model; - this.listenTo(model.messages, 'add', this.requestUpdate); - this.listenTo(model.messages, 'change', this.requestUpdate); - this.listenTo(model.messages, 'remove', this.requestUpdate); - this.listenTo(model.messages, 'reset', this.requestUpdate); - this.listenTo(model.notifications, 'change', this.requestUpdate); - if (model.occupants) { - this.listenTo(model.occupants, 'change', this.requestUpdate); + this.model = _converse.chatboxes.get(this.jid); + this.listenTo(this.model.messages, 'add', this.requestUpdate); + this.listenTo(this.model.messages, 'change', this.requestUpdate); + this.listenTo(this.model.messages, 'remove', this.requestUpdate); + this.listenTo(this.model.messages, 'reset', this.requestUpdate); + this.listenTo(this.model.notifications, 'change', this.requestUpdate); + if (this.model.occupants) { + this.listenTo(this.model.occupants, 'change', this.requestUpdate); } + + // We jot down whether we were scrolled down before rendering, because when an + // image loads, it triggers 'scroll' and the chat will be marked as scrolled, + // which is technically true, but not what we want because the user + // didn't initiate the scrolling. + this.was_scrolled_up = this.model.get('scrolled'); + this.addEventListener('imageLoaded', () => { + !this.was_scrolled_up && this.scrollDown(); + }); } render () { - const notifications = xss.filterXSS(this.chatview.getNotifications(), {'whiteList': {}}); return html` + .model=${this.model} + .messages=${[...this.model.messages.models]}> -
${unsafeHTML(notifications)}
+
${this.model.getNotificationsText()}
`; } + + scrollDown () { + if (this.scrollTo) { + const behavior = this.scrollTop ? 'smooth' : 'auto'; + this.scrollTo({ 'top': this.scrollHeight, behavior }); + } else { + this.scrollTop = this.scrollHeight; + } + } } api.elements.define('converse-chat-content', ChatContent); diff --git a/src/components/message-actions.js b/src/components/message-actions.js index 0864ca8ce..63b5217fe 100644 --- a/src/components/message-actions.js +++ b/src/components/message-actions.js @@ -1,15 +1,17 @@ +import log from '@converse/headless/log'; import { CustomElement } from './element.js'; import { __ } from '../i18n'; -import { api } from "@converse/headless/core"; +import { _converse, api, converse } from "@converse/headless/core"; import { html } from 'lit-element'; import { until } from 'lit-html/directives/until.js'; +const { Strophe, u } = converse.env; + class MessageActions extends CustomElement { static get properties () { return { - chatview: { type: Object }, model: { type: Object }, editable: { type: Boolean }, correcting: { type: Boolean }, @@ -22,6 +24,16 @@ class MessageActions extends CustomElement { return html`${ until(this.renderActions(), '') }`; } + async renderActions () { + const buttons = await this.getActionButtons(); + const items = buttons.map(b => MessageActions.getActionsDropdownItem(b)); + if (items.length) { + return html``; + } else { + return ''; + } + } + static getActionsDropdownItem (o) { return html`