Browse Source

Add support for editing messages containing mentions

JC Brand 6 năm trước cách đây
mục cha
commit
2db3db9bab

+ 76 - 3
spec/messages.js

@@ -2091,7 +2091,7 @@
 
 
         describe("when received", function () {
         describe("when received", function () {
 
 
-            it("highlights all users mentioned via XEP-0372 references", 
+            it("highlights all users mentioned via XEP-0372 references",
                 mock.initConverseWithPromises(
                 mock.initConverseWithPromises(
                     null, ['rosterGroupsFetched'], {},
                     null, ['rosterGroupsFetched'], {},
                         function (done, _converse) {
                         function (done, _converse) {
@@ -2137,7 +2137,7 @@
 
 
         describe("in which someone is mentioned", function () {
         describe("in which someone is mentioned", function () {
 
 
-            it("gets parsed for mentions which get turned into references", 
+            it("gets parsed for mentions which get turned into references",
                 mock.initConverseWithPromises(
                 mock.initConverseWithPromises(
                     null, ['rosterGroupsFetched'], {},
                     null, ['rosterGroupsFetched'], {},
                         function (done, _converse) {
                         function (done, _converse) {
@@ -2190,12 +2190,85 @@
                     expect(references.length).toBe(1);
                     expect(references.length).toBe(1);
                     expect(JSON.stringify(references))
                     expect(JSON.stringify(references))
                         .toBe('[{"begin":0,"end":6,"value":"gibson","type":"mention","uri":"xmpp:gibson@localhost"}]');
                         .toBe('[{"begin":0,"end":6,"value":"gibson","type":"mention","uri":"xmpp:gibson@localhost"}]');
-
                     done();
                     done();
                     return;
                     return;
                 });
                 });
             }));
             }));
 
 
+            it("can get corrected and given new references",
+                mock.initConverseWithPromises(
+                    null, ['rosterGroupsFetched'], {},
+                        function (done, _converse) {
+
+                test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'tom')
+                .then(() => {
+                    const view = _converse.chatboxviews.get('lounge@localhost');
+                    ['z3r0', 'mr.robot', 'gibson', 'sw0rdf1sh'].forEach((nick) => {
+                        _converse.connection._dataRecv(test_utils.createRequest(
+                            $pres({
+                                'to': 'tom@localhost/resource',
+                                'from': `lounge@localhost/${nick}`
+                            })
+                            .c('x', {xmlns: Strophe.NS.MUC_USER})
+                            .c('item', {
+                                'affiliation': 'none',
+                                'jid': `${nick}@localhost/resource`,
+                                'role': 'participant'
+                            })));
+                    });
+
+                    const textarea = view.el.querySelector('textarea.chat-textarea');
+                    textarea.value = 'hello @z3r0 @gibson @mr.robot, how are you?'
+                    const enter_event = {
+                        'target': textarea,
+                        'preventDefault': _.noop,
+                        'stopPropagation': _.noop,
+                        'keyCode': 13 // Enter
+                    }
+
+                    spyOn(_converse.connection, 'send');
+                    view.keyPressed(enter_event);
+                    const msg = _converse.connection.send.calls.all()[0].args[0];
+                    expect(msg.toLocaleString())
+                        .toBe(`<message from='dummy@localhost/resource' `+
+                                `to='lounge@localhost' type='groupchat' id='${msg.nodeTree.getAttribute('id')}' `+
+                                `xmlns='jabber:client'>`+
+                                    `<body>hello z3r0 gibson mr.robot, how are you?</body>`+
+                                    `<active xmlns='http://jabber.org/protocol/chatstates'/>`+
+                                    `<reference xmlns='urn:xmpp:reference:0' begin='18' end='26' type='mention' uri='xmpp:mr.robot@localhost'/>`+
+                                    `<reference xmlns='urn:xmpp:reference:0' begin='11' end='17' type='mention' uri='xmpp:gibson@localhost'/>`+
+                                    `<reference xmlns='urn:xmpp:reference:0' begin='6' end='10' type='mention' uri='xmpp:z3r0@localhost'/>`+
+                              `</message>`);
+
+                    const first_msg = view.model.messages.findWhere({'message': 'hello z3r0 gibson mr.robot, how are you?'});
+                    const action = view.el.querySelector('.chat-msg .chat-msg__action');
+                    action.style.opacity = 1;
+                    action.click();
+
+                    expect(textarea.value).toBe('hello @z3r0 @gibson @mr.robot, how are you?');
+                    expect(view.model.messages.at(0).get('correcting')).toBe(true);
+                    expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
+                    expect(u.hasClass('correcting', view.el.querySelector('.chat-msg'))).toBe(true);
+
+                    textarea.value = 'hello @z3r0 @gibson @sw0rdf1sh, how are you?';
+                    view.keyPressed(enter_event);
+
+                    const correction = _converse.connection.send.calls.all()[1].args[0];
+                    expect(correction.toLocaleString())
+                        .toBe(`<message from='dummy@localhost/resource' `+
+                                `to='lounge@localhost' type='groupchat' id='${correction.nodeTree.getAttribute('id')}' `+
+                                `xmlns='jabber:client'>`+
+                                    `<body>hello z3r0 gibson sw0rdf1sh, how are you?</body>`+
+                                    `<active xmlns='http://jabber.org/protocol/chatstates'/>`+
+                                    `<reference xmlns='urn:xmpp:reference:0' begin='18' end='27' type='mention' uri='xmpp:sw0rdf1sh@localhost'/>`+
+                                    `<reference xmlns='urn:xmpp:reference:0' begin='11' end='17' type='mention' uri='xmpp:gibson@localhost'/>`+
+                                    `<reference xmlns='urn:xmpp:reference:0' begin='6' end='10' type='mention' uri='xmpp:z3r0@localhost'/>`+
+                                    `<replace xmlns='urn:xmpp:message-correct:0' id='${msg.nodeTree.getAttribute('id')}'/>`+
+                              `</message>`);
+                    done();
+                }).catch(_.partial(console.error, _));
+            }));
+
             it("includes XEP-0372 references to that person",
             it("includes XEP-0372 references to that person",
                 mock.initConverseWithPromises(
                 mock.initConverseWithPromises(
                     null, ['rosterGroupsFetched'], {},
                     null, ['rosterGroupsFetched'], {},

+ 3 - 2
src/converse-chatboxes.js

@@ -400,10 +400,11 @@
                         const older_versions = message.get('older_versions') || [];
                         const older_versions = message.get('older_versions') || [];
                         older_versions.push(message.get('message'));
                         older_versions.push(message.get('message'));
                         message.save({
                         message.save({
+                            'correcting': false,
+                            'edited': true,
                             'message': attrs.message,
                             'message': attrs.message,
                             'older_versions': older_versions,
                             'older_versions': older_versions,
-                            'edited': true,
-                            'correcting': false
+                            'references': attrs.references
                         });
                         });
                         return this.sendMessageStanza(message);
                         return this.sendMessageStanza(message);
                     }
                     }

+ 1 - 1
src/converse-chatview.js

@@ -970,7 +970,7 @@
                             currently_correcting.save('correcting', false);
                             currently_correcting.save('correcting', false);
                         }
                         }
                         message.save('correcting', true);
                         message.save('correcting', true);
-                        this.insertIntoTextArea(message.get('message'), true, true);
+                        this.insertIntoTextArea(u.prefixMentions(message), true, true);
                     } else {
                     } else {
                         message.save('correcting', false);
                         message.save('correcting', false);
                         this.insertIntoTextArea('', true, false);
                         this.insertIntoTextArea('', true, false);

+ 1 - 1
src/converse-message-view.js

@@ -167,7 +167,7 @@
                         text = xss.filterXSS(text, {'whiteList': {}});
                         text = xss.filterXSS(text, {'whiteList': {}});
                         msg_content.innerHTML = _.flow(
                         msg_content.innerHTML = _.flow(
                             _.partial(u.geoUriToHttp, _, _converse.geouri_replacement),
                             _.partial(u.geoUriToHttp, _, _converse.geouri_replacement),
-                            _.partial(u.addMentions, _, this.model.get('references'), this.model.collection.chatbox),
+                            _.partial(u.addMentionsMarkup, _, this.model.get('references'), this.model.collection.chatbox),
                             u.addHyperlinks,
                             u.addHyperlinks,
                             u.renderNewLines,
                             u.renderNewLines,
                             _.partial(u.addEmoji, _converse, emojione, _)
                             _.partial(u.addEmoji, _converse, emojione, _)

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

@@ -518,6 +518,7 @@
                 is_chatroom: true,
                 is_chatroom: true,
                 events: {
                 events: {
                     'change input.fileupload': 'onFileSelection',
                     'change input.fileupload': 'onFileSelection',
+                    'click .chat-msg__action-edit': 'onMessageEditButtonClicked',
                     'click .chatbox-navback': 'showControlBox',
                     'click .chatbox-navback': 'showControlBox',
                     'click .close-chatbox-button': 'close',
                     'click .close-chatbox-button': 'close',
                     'click .configure-chatroom-button': 'getAndRenderConfigurationForm',
                     'click .configure-chatroom-button': 'getAndRenderConfigurationForm',

+ 14 - 1
src/utils/core.js

@@ -229,7 +229,20 @@
         return encodeURI(decodeURI(url)).replace(/[!'()]/g, escape).replace(/\*/g, "%2A");
         return encodeURI(decodeURI(url)).replace(/[!'()]/g, escape).replace(/\*/g, "%2A");
     };
     };
 
 
-    u.addMentions = function (text, references, chatbox) {
+    u.prefixMentions = function (message) {
+        /* Given a message object, return its text with @ chars
+         * inserted before the mentioned nicknames.
+         */
+        let text = message.get('message');
+        (message.get('references') || [])
+            .sort((a, b) => b.begin - a.begin)
+            .forEach(ref => {
+                text = `${text.slice(0, ref.begin)}@${text.slice(ref.begin)}`
+            });
+        return text;
+    };
+
+    u.addMentionsMarkup = function (text, references, chatbox) {
         if (chatbox.get('message_type') !== 'groupchat') {
         if (chatbox.get('message_type') !== 'groupchat') {
             return text;
             return text;
         }
         }