Ver código fonte

Allow setting a nickname when adding a roster contact

JC Brand 7 anos atrás
pai
commit
4f2b040f22
3 arquivos alterados com 101 adições e 38 exclusões
  1. 48 7
      spec/controlbox.js
  2. 45 29
      src/converse-rosterview.js
  3. 8 2
      src/templates/add_contact_modal.html

+ 48 - 7
spec/controlbox.js

@@ -197,12 +197,27 @@
             return test_utils.waitUntil(function () {
                 return u.isVisible(modal.el);
             }, 1000).then(function () {
+                var sendIQ = _converse.connection.sendIQ;
+                var sent_stanza, IQ_id;
+                spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
+                    sent_stanza = iq;
+                    IQ_id = sendIQ.bind(this)(iq, callback, errback);
+                });
+
                 expect(!_.isNull(modal.el.querySelector('form.add-xmpp-contact'))).toBeTruthy();
-                var input_el = modal.el.querySelector('input[name="jid"]');
-                input_el.value = 'someone@';
+                var input_jid = modal.el.querySelector('input[name="jid"]');
+                var input_name = modal.el.querySelector('input[name="name"]');
+                input_jid.value = 'someone@';
                 var evt = new Event('input');
-                input_el.dispatchEvent(evt);
+                input_jid.dispatchEvent(evt);
                 expect(modal.el.querySelector('.awesomplete li').textContent).toBe('someone@localhost');
+                input_jid.value = 'someone@localhost';
+                input_name.value = 'Someone';
+                modal.el.querySelector('button[type="submit"]').click();
+                expect(sent_stanza.toLocaleString()).toEqual(
+                "<iq type='set' xmlns='jabber:client' id='"+IQ_id+"'>"+
+                    "<query xmlns='jabber:iq:roster'><item jid='someone@localhost' name='Someone'/></query>"+
+                "</iq>");
                 done();
             });
         }));
@@ -231,6 +246,7 @@
                 return xhr;
             });
 
+            var input_el;
             var panel = _converse.chatboxviews.get('controlbox').contactspanel;
             var cbview = _converse.chatboxviews.get('controlbox');
             cbview.el.querySelector('.add-contact').click()
@@ -238,15 +254,40 @@
             return test_utils.waitUntil(function () {
                 return u.isVisible(modal.el);
             }, 1000).then(function () {
-                var input_el = modal.el.querySelector('input[name="jid"]');
-                input_el.value = 'marty@';
+                input_el = modal.el.querySelector('input[name="name"]');
+                input_el.value = 'marty';
                 var evt = new Event('input');
                 input_el.dispatchEvent(evt);
                 return test_utils.waitUntil(function () {
                     return modal.el.querySelector('.awesomplete li');
-                });
+                }, 1000);
             }).then(function () {
-                expect(modal.el.querySelector('.awesomplete li').textContent).toBe('marty@mcfly.net');
+                var sendIQ = _converse.connection.sendIQ;
+                var sent_stanza, IQ_id;
+                spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
+                    sent_stanza = iq;
+                    IQ_id = sendIQ.bind(this)(iq, callback, errback);
+                });
+                expect(modal.el.querySelectorAll('.awesomplete li').length).toBe(1);
+                const suggestion = modal.el.querySelector('.awesomplete li');
+                expect(suggestion.textContent).toBe('Marty McFly');
+
+                // Can't trigger "mousedown" event so trigger the Awesomplete
+                // custom event which would have been triggered upon mousedown.
+                var evt = document.createEvent("HTMLEvents");
+                evt.initEvent('awesomplete-selectcomplete', true, true );
+                evt.text = {
+                    'label': 'Marty McFly',
+                    'value': 'marty@mcfly.net'
+                }
+                modal.el.dispatchEvent(evt);
+                expect(input_el.value).toBe('Marty McFly');
+                expect(modal.el.querySelector('input[name="jid"]').value).toBe('marty@mcfly.net');
+                modal.el.querySelector('button[type="submit"]').click();
+                expect(sent_stanza.toLocaleString()).toEqual(
+                "<iq type='set' xmlns='jabber:client' id='"+IQ_id+"'>"+
+                    "<query xmlns='jabber:iq:roster'><item jid='marty@mcfly.net' name='Marty McFly'/></query>"+
+                "</iq>");
                 done();
             });
         }));

+ 45 - 29
src/converse-rosterview.js

@@ -131,8 +131,7 @@
 
             _converse.AddContactModal = _converse.BootstrapModal.extend({
                 events: {
-                    'submit form': 'addContactFromForm',
-                    'submit form.search-xmpp-contact': 'searchContacts'
+                    'submit form': 'addContactFromForm'
                 },
 
                 initialize () {
@@ -141,49 +140,66 @@
                 },
 
                 toHTML () {
+                    const label_nickname = _converse.xhr_user_search_url ? __('Contact name') : __('Optional nickname');
                     return tpl_add_contact_modal(_.extend(this.model.toJSON(), {
+                        '_converse': _converse,
                         'heading_new_contact': __('Add a Contact'),
                         'label_xmpp_address': __('XMPP Address'),
-                        'label_nickname': __('Optional nickname'),
+                        'label_nickname': label_nickname,
                         'contact_placeholder': __('name@example.org'),
                         'label_add': __('Add'),
                     }));
                 },
 
                 afterRender () {
-                    const input_el = this.el.querySelector('input[name="jid"]');
                     if (_converse.xhr_user_search_url && _.isString(_converse.xhr_user_search_url)) {
-                        const awesomplete = new Awesomplete(input_el, {'list': []});
-                        const xhr = new window.XMLHttpRequest();
-                        // `open` must be called after `onload` for mock/testing purposes.
-                        xhr.onload = function () {
-                            if (xhr.responseText) {
-                                awesomplete.list = JSON.parse(xhr.responseText).map((i) => {
-                                    return {'label': i.fullname, 'value': i.jid};
-                                });
-                                awesomplete.evaluate();
-                            }
-                        };
-                        input_el.addEventListener('input', _.debounce(() => {
-                            xhr.open("GET", `${_converse.xhr_user_search_url}?q=${input_el.value}`, true);
-                            xhr.send()
-                        } , 500));
+                        this.initXHRAutoComplete();
                     } else {
-                        const list = _.uniq(_converse.roster.map((item) => Strophe.getDomainFromJid(item.get('jid'))));
-                        new Awesomplete(input_el, {
-                            'list': list,
-                            'data': function (text, input) {
-                                return input.slice(0, input.indexOf("@")) + "@" + text;
-                            },
-                            'filter': Awesomplete.FILTER_STARTSWITH
-                        });
+                        this.initJIDAutoComplete();
                     }
                 },
 
+                initJIDAutoComplete () {
+                    const input_el = this.el.querySelector('input[name="jid"]');
+                    const list = _.uniq(_converse.roster.map((item) => Strophe.getDomainFromJid(item.get('jid'))));
+                    new Awesomplete(input_el, {
+                        'list': list,
+                        'data': function (text, input) {
+                            return input.slice(0, input.indexOf("@")) + "@" + text;
+                        },
+                        'filter': Awesomplete.FILTER_STARTSWITH
+                    });
+                },
+
+                initXHRAutoComplete () {
+                    const name_input = this.el.querySelector('input[name="name"]');
+                    const jid_input = this.el.querySelector('input[name="jid"]');
+                    const awesomplete = new Awesomplete(name_input, {'list': []});
+                    const xhr = new window.XMLHttpRequest();
+                    // `open` must be called after `onload` for mock/testing purposes.
+                    xhr.onload = function () {
+                        if (xhr.responseText) {
+                            awesomplete.list = JSON.parse(xhr.responseText).map((i) => { //eslint-disable-line arrow-body-style
+                                return {'label': i.fullname, 'value': i.jid};
+                            });
+                            awesomplete.evaluate();
+                        }
+                    };
+                    name_input.addEventListener('input', _.debounce(() => {
+                        xhr.open("GET", `${_converse.xhr_user_search_url}?q=${name_input.value}`, true);
+                        xhr.send()
+                    } , 300));
+                    this.el.addEventListener('awesomplete-selectcomplete', (ev) => {
+                        jid_input.value = ev.text.value;
+                        name_input.value = ev.text.label;
+                    });
+                },
+
                 addContactFromForm (ev) {
                     ev.preventDefault();
                     const data = new FormData(ev.target),
-                          jid = data.get('jid');
+                          jid = data.get('jid'),
+                          name = data.get('name');
 
                     if (!jid || _.compact(jid.split('@')).length < 2) {
                         this.model.set({
@@ -191,7 +207,7 @@
                             'jid': jid
                         })
                     } else {
-                        _converse.roster.addAndSubscribe(jid);
+                        _converse.roster.addAndSubscribe(jid, name);
                         this.model.clear();
                         this.modal.hide();
                     }

+ 8 - 2
src/templates/add_contact_modal.html

@@ -8,15 +8,21 @@
             </div>
             <form class="converse-form add-xmpp-contact">
                 <div class="modal-body">
-                    <div class="form-group">
+                    <div class="form-group {[ if (o._converse.xhr_user_search_url) { ]} hidden {[ } ]}">
                         <label class="clearfix" for="jid">{{{o.label_xmpp_address}}}:</label>
                         <input type="text" name="jid" required="required" value="{{{o.jid}}}"
                                class="form-control {[ if (o.error_message) { ]} is-invalid {[ } ]}"
-                               placeholder="{{{o.contact_placeholder}}}">
+                               placeholder="{{{o.contact_placeholder}}}"/>
                         {[ if (o.error_message) { ]}
                             <div class="invalid-feedback">{{{o.error_message}}}</div>
                         {[ } ]}
                     </div>
+                    <div class="form-group">
+                        <label class="clearfix" for="name">{{{o.label_nickname}}}:</label>
+                        <input type="text" name="name" value="{{{o.nickname}}}"
+                               class="form-control {[ if (o.error_message) { ]} is-invalid {[ } ]}"
+                               placeholder="{{{o.nickname_placeholder}}}"/>
+                    </div>
                 </div>
                 <div class="modal-footer">
                     <button type="submit" class="btn btn-primary">{{{o.label_add}}}</button>