瀏覽代碼

MUC: Don't show topic change notification for old changes.

Also, show topic by creating a message object, instead of directly
inserting HTML into the DOM. This is a necessary precursor to being able
to render chat messages via lit-html/lit-element.
JC Brand 5 年之前
父節點
當前提交
5fd316816d
共有 4 個文件被更改,包括 71 次插入49 次删除
  1. 48 17
      spec/muc.js
  2. 2 2
      spec/xss.js
  3. 0 21
      src/converse-muc-views.js
  4. 21 9
      src/headless/converse-muc.js

+ 48 - 17
spec/muc.js

@@ -501,7 +501,7 @@
                 });
             });
 
-            describe("the topic", function () {
+            describe("topic", function () {
 
                 it("is shown the header",
                     mock.initConverse(
@@ -511,7 +511,7 @@
                     await test_utils.openAndEnterChatRoom(_converse, 'jdev@conference.jabber.org', 'jc');
                     const text = 'Jabber/XMPP Development | RFCs and Extensions: https://xmpp.org/ | Protocol and XSF discussions: xsf@muc.xmpp.org';
                     let stanza = u.toStanza(`
-                        <message xmlns="jabber:client" to="jc@opkode.com/_converse.js-60429116" type="groupchat" from="jdev@conference.jabber.org/ralphm">
+                        <message xmlns="jabber:client" to="${_converse.jid}" type="groupchat" from="jdev@conference.jabber.org/ralphm">
                             <subject>${text}</subject>
                             <delay xmlns="urn:xmpp:delay" stamp="2014-02-04T09:35:39Z" from="jdev@conference.jabber.org"/>
                             <x xmlns="jabber:x:delay" stamp="20140204T09:35:39" from="jdev@conference.jabber.org"/>
@@ -520,12 +520,11 @@
                     const view = _converse.chatboxviews.get('jdev@conference.jabber.org');
                     await new Promise(resolve => view.model.once('change:subject', resolve));
 
-                    expect(sizzle('.chat-event:last', view.el).pop().textContent.trim()).toBe('Topic set by ralphm');
                     const head_desc = await u.waitUntil(() => view.el.querySelector('.chat-head__desc'));
                     expect(head_desc?.textContent.trim()).toBe(text);
 
                     stanza = u.toStanza(
-                        `<message xmlns="jabber:client" to="jc@opkode.com/_converse.js-60429116" type="groupchat" from="jdev@conference.jabber.org/ralphm">
+                        `<message xmlns="jabber:client" to="${_converse.jid}" type="groupchat" from="jdev@conference.jabber.org/ralphm">
                             <subject>This is a message subject</subject>
                             <body>This is a message</body>
                         </message>`);
@@ -536,16 +535,6 @@
                     expect(sizzle('.chat-msg__text').length).toBe(1);
                     expect(sizzle('.chat-msg__text').pop().textContent.trim()).toBe('This is a message');
                     expect(view.el.querySelector('.chat-head__desc').textContent.trim()).toBe(text);
-
-                    // Removes current topic
-                    stanza = u.toStanza(
-                        `<message xmlns="jabber:client" to="jc@opkode.com/_converse.js-60429116" type="groupchat" from="jdev@conference.jabber.org/ralphm">
-                            <subject/>
-                        </message>`);
-                    _converse.connection._dataRecv(test_utils.createRequest(stanza));
-                    await new Promise(resolve => view.model.once('change:subject', resolve));
-                    await u.waitUntil(() => view.el.querySelector('.chat-head__desc') === null);
-                    expect(view.el.querySelector('.chat-info:last-child').textContent.trim()).toBe("Topic cleared by ralphm");
                     done();
                 }));
 
@@ -557,7 +546,7 @@
                     await test_utils.openAndEnterChatRoom(_converse, 'jdev@conference.jabber.org', 'jc');
                     const text = 'Jabber/XMPP Development | RFCs and Extensions: https://xmpp.org/ | Protocol and XSF discussions: xsf@muc.xmpp.org';
                     let stanza = u.toStanza(`
-                        <message xmlns="jabber:client" to="jc@opkode.com/_converse.js-60429116" type="groupchat" from="jdev@conference.jabber.org/ralphm">
+                        <message xmlns="jabber:client" to="${_converse.jid}" type="groupchat" from="jdev@conference.jabber.org/ralphm">
                             <subject>${text}</subject>
                             <delay xmlns="urn:xmpp:delay" stamp="2014-02-04T09:35:39Z" from="jdev@conference.jabber.org"/>
                             <x xmlns="jabber:x:delay" stamp="20140204T09:35:39" from="jdev@conference.jabber.org"/>
@@ -566,12 +555,11 @@
                     const view = _converse.chatboxviews.get('jdev@conference.jabber.org');
                     await new Promise(resolve => view.model.once('change:subject', resolve));
 
-                    expect(sizzle('.chat-event:last', view.el).pop().textContent.trim()).toBe('Topic set by ralphm');
                     const head_desc = await u.waitUntil(() => view.el.querySelector('.chat-head__desc'));
                     expect(head_desc?.textContent.trim()).toBe(text);
 
                     stanza = u.toStanza(
-                        `<message xmlns="jabber:client" to="jc@opkode.com/_converse.js-60429116" type="groupchat" from="jdev@conference.jabber.org/ralphm">
+                        `<message xmlns="jabber:client" to="${_converse.jid}" type="groupchat" from="jdev@conference.jabber.org/ralphm">
                             <subject>This is a message subject</subject>
                             <body>This is a message</body>
                         </message>`);
@@ -592,6 +580,49 @@
                     expect(view.el.querySelector('.hide-topic').textContent).toBe('Show topic');
                     done();
                 }));
+
+                it("causes an info message to be shown when received in real-time",
+                    mock.initConverse(
+                        ['rosterGroupsFetched'], {},
+                        async function (done, _converse) {
+
+                    spyOn(_converse.ChatRoom.prototype, 'handleSubjectChange').and.callThrough();
+                    await test_utils.openAndEnterChatRoom(_converse, 'jdev@conference.jabber.org', 'romeo');
+                    const view = _converse.chatboxviews.get('jdev@conference.jabber.org');
+
+                    _converse.connection._dataRecv(test_utils.createRequest(u.toStanza(`
+                        <message xmlns="jabber:client" to="${_converse.jid}" type="groupchat" from="jdev@conference.jabber.org/ralphm">
+                            <subject>This is an older topic</subject>
+                            <delay xmlns="urn:xmpp:delay" stamp="2014-02-04T09:35:39Z" from="jdev@conference.jabber.org"/>
+                            <x xmlns="jabber:x:delay" stamp="20140204T09:35:39" from="jdev@conference.jabber.org"/>
+                        </message>`)));
+                    await u.waitUntil(() => view.model.handleSubjectChange.calls.count());
+                    expect(sizzle('.chat-info__message', view.el).length).toBe(0);
+
+                    const desc = await u.waitUntil(() => view.el.querySelector('.chat-head__desc'));
+                    expect(desc.textContent.trim()).toBe('This is an older topic');
+
+                    _converse.connection._dataRecv(test_utils.createRequest(u.toStanza(`
+                        <message xmlns="jabber:client" to="${_converse.jid}" type="groupchat" from="jdev@conference.jabber.org/ralphm">
+                            <subject>This is a new topic</subject>
+                        </message>`)));
+                    await u.waitUntil(() => view.model.handleSubjectChange.calls.count() === 2);
+
+                    const el = sizzle('.chat-info__message', view.el).pop();
+                    expect(el.textContent.trim()).toBe('Topic set by ralphm');
+                    await u.waitUntil(() => desc.textContent.trim()  === 'This is a new topic');
+
+                    // Removes current topic
+                    const stanza = u.toStanza(
+                        `<message xmlns="jabber:client" to="${_converse.jid}" type="groupchat" from="jdev@conference.jabber.org/ralphm">
+                            <subject/>
+                        </message>`);
+                    _converse.connection._dataRecv(test_utils.createRequest(stanza));
+                    await u.waitUntil(() => view.model.handleSubjectChange.calls.count() === 3);
+                    await u.waitUntil(() => view.el.querySelector('.chat-head__desc') === null);
+                    expect(view.el.querySelector('.chat-info:last-child').textContent.trim()).toBe("Topic cleared by ralphm");
+                    done();
+                }));
             });
 
 

+ 2 - 2
spec/xss.js

@@ -235,8 +235,8 @@
                     'text': subject,
                     'author': 'ralphm'
                 }});
-                expect(sizzle('.chat-event:last').pop().textContent.trim()).toBe('Topic set by ralphm');
-                await u.waitUntil(() => view.el.querySelector('.chat-head__desc')?.textContent.trim() === subject);
+                const text = await u.waitUntil(() => view.el.querySelector('.chat-head__desc')?.textContent.trim());
+                expect(text).toBe(subject);
                 done();
             }));
         });

+ 0 - 21
src/converse-muc-views.js

@@ -708,7 +708,6 @@ converse.plugins.add('converse-muc-views', {
 
                 this.listenTo(this.model, 'change', debounce(() => this.renderHeading(), 250));
                 this.listenTo(this.model, 'change:hidden_occupants', this.updateOccupantsToggle);
-                this.listenTo(this.model, 'change:subject', this.setChatRoomSubject);
                 this.listenTo(this.model, 'configurationNeeded', this.getAndRenderConfigurationForm);
                 this.listenTo(this.model, 'destroy', this.hide);
                 this.listenTo(this.model, 'show', this.show);
@@ -2004,26 +2003,6 @@ converse.plugins.add('converse-muc-views', {
                     this.renderAfterTransition();
                 }
                 return this;
-            },
-
-            setChatRoomSubject () {
-                const subject = this.model.get('subject');
-                if (!subject.text && !subject.author) {
-                    return; // Probably a new MUC
-                }
-                const author = subject.author;
-                // For translators: the %1$s part will get
-                // replaced by the user's name.
-                // Example: Topic set by JC Brand
-                const message = subject.text ? __('Topic set by %1$s', author) : __('Topic cleared by %1$s', author);
-                this.msgs_container.insertAdjacentHTML(
-                    'beforeend',
-                    tpl_info({
-                        'isodate': (new Date()).toISOString(),
-                        'extra_classes': 'chat-event',
-                        'message': message
-                    }));
-                this.scrollDown();
             }
         });
 

+ 21 - 9
src/headless/converse-muc.js

@@ -1682,22 +1682,34 @@ converse.plugins.add('converse-muc', {
             },
 
             /**
-             * Handle a subject change and return `true` if so.
+             * Handle a possible subject change and return `true` if so.
              * @private
-             * @method _converse.ChatRoom#subjectChangeHandled
-             * @param { object } attrs - The message attributes
+             * @method _converse.ChatRoom#handleSubjectChange
+             * @param { object } attrs - Attributes representing a received
+             *  message, as returned by {@link stanza_utils.getMessageAttributesFromStanza}
              */
-            subjectChangeHandled (attrs) {
+            handleSubjectChange (attrs) {
                 if (isString(attrs.subject) && !attrs.thread && !attrs.message) {
                     // https://xmpp.org/extensions/xep-0045.html#subject-mod
                     // -----------------------------------------------------
                     // The subject is changed by sending a message of type "groupchat" to the <room@service>,
                     // where the <message/> MUST contain a <subject/> element that specifies the new subject but
                     // MUST NOT contain a <body/> element (or a <thread/> element).
+                    const subject = attrs.subject;
+                    const author = attrs.nick;
                     u.safeSave(this, {
-                        'subject': {'author': attrs.nick, 'text': attrs.subject || ''},
-                        'subject_hidden': attrs.subject ? false : this.get('subject_hidden')
+                        'subject': {author, 'text': attrs.subject || ''},
+                        'subject_hidden': subject ? false : this.get('subject_hidden')
                     });
+                    if (!attrs.is_delayed) {
+                        const message = subject ? __('Topic set by %1$s', author) : __('Topic cleared by %1$s', author);
+                        const data = {
+                            message,
+                            'nick': attrs.nick,
+                            'type': 'info'
+                        };
+                        this.createMessage(data);
+                     }
                     return true;
                 }
                 return false;
@@ -1998,7 +2010,7 @@ converse.plugins.add('converse-muc', {
 
                 if (await this.handleRetraction(attrs) ||
                         await this.handleModeration(attrs) ||
-                        this.subjectChangeHandled(attrs) ||
+                        this.handleSubjectChange(attrs) ||
                         this.ignorableCSN(attrs)) {
                     return api.trigger('message', {'stanza': original_stanza});
                 }
@@ -2070,10 +2082,10 @@ converse.plugins.add('converse-muc', {
 
 
             /**
-             * Create info messages based on a received presence stanza
+             * Create info messages based on a received presence or message stanza
              * @private
              * @method _converse.ChatRoom#createInfoMessages
-             * @param { XMLElement } stanza: The presence stanza received
+             * @param { XMLElement } stanza
              */
             createInfoMessages (stanza) {
                 const is_self = stanza.querySelector("status[code='110']") !== null;