瀏覽代碼

Let `@` trigger autocomplete with all possible options shown

JC Brand 6 年之前
父節點
當前提交
324ffd5e40
共有 3 個文件被更改,包括 66 次插入50 次删除
  1. 46 13
      spec/autocomplete.js
  2. 18 36
      src/converse-autocomplete.js
  3. 2 1
      src/utils/core.js

+ 46 - 13
spec/autocomplete.js

@@ -15,6 +15,50 @@
 
     return describe("A groupchat textarea", function () {
 
+        it("shows all autocompletion options when the user presses @",
+            mock.initConverseWithPromises(
+                null, ['rosterGroupsFetched'], {},
+                    function (done, _converse) {
+
+            test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'tom')
+            .then(() => {
+                const view = _converse.chatboxviews.get('lounge@localhost');
+
+                ['dick', 'harry'].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'
+                        })));
+                });
+
+                // Test that pressing @ brings up all options
+                const textarea = view.el.querySelector('textarea.chat-textarea');
+                const at_event = {
+                    'target': textarea,
+                    'preventDefault': _.noop,
+                    'stopPropagation': _.noop,
+                    'keyCode': 50
+                };
+                view.keyPressed(at_event);
+                textarea.value = '@';
+                view.keyUp(at_event);
+
+                expect(view.el.querySelectorAll('.suggestion-box__results li').length).toBe(3);
+                expect(view.el.querySelector('.suggestion-box__results li[aria-selected="true"]').textContent).toBe('tom');
+                expect(view.el.querySelector('.suggestion-box__results li:first-child').textContent).toBe('tom');
+                expect(view.el.querySelector('.suggestion-box__results li:nth-child(2)').textContent).toBe('dick');
+                expect(view.el.querySelector('.suggestion-box__results li:nth-child(3)').textContent).toBe('harry');
+                done();
+            }).catch(_.partial(console.error, _));
+        }));
+
         it("autocompletes when the user presses tab",
             mock.initConverseWithPromises(
                 null, ['rosterGroupsFetched'], {},
@@ -102,7 +146,7 @@
                     'stopPropagation': _.noop,
                     'keyCode': 13 // Enter
                 });
-                expect(textarea.value).toBe('hello s some2');
+                expect(textarea.value).toBe('hello s some2 ');
 
                 // Test that pressing tab twice selects
                 presence = $pres({
@@ -122,18 +166,7 @@
 
                 view.keyPressed(tab_event);
                 view.keyUp(tab_event);
-                expect(textarea.value).toBe('hello z3r0');
-
-                // Test that pressing @ brings up all options
-                const at_event = {
-                    'target': textarea,
-                    'preventDefault': _.noop,
-                    'stopPropagation': _.noop,
-                    'keyCode': 50
-                };
-                view.keyPressed(at_event);
-                view.keyUp(at_event);
-                textarea.value = 'hello z3r0 and @';
+                expect(textarea.value).toBe('hello z3r0 ');
 
                 done();
             }).catch(_.partial(console.error, _));

+ 18 - 36
src/converse-autocomplete.js

@@ -193,8 +193,7 @@
                     if (this.auto_first && this.index === -1) {
                         this.goto(0);
                     }
-
-                    helpers.fire(this.input, "suggestion-box-open");
+                    this.trigger("suggestion-box-open");
                 }
 
                 destroy () {
@@ -250,18 +249,11 @@
                     }
 
                     if (selected) {
-                        const suggestion = this.suggestions[this.index],
-                            allowed = helpers.fire(this.input, "suggestion-box-select", {
-                                'text': suggestion,
-                                'origin': origin || selected
-                            });
-
-                        if (allowed) {
-                            this.insertValue(suggestion);
-                            this.close({'reason': 'select'});
-                            this.auto_completing = false;
-                            this.trigger("suggestion-box-selectcomplete", {'text': suggestion});
-                        }
+                        const suggestion = this.suggestions[this.index];
+                        this.insertValue(suggestion);
+                        this.close({'reason': 'select'});
+                        this.auto_completing = false;
+                        this.trigger("suggestion-box-selectcomplete", {'text': suggestion});
                     }
                 }
 
@@ -309,17 +301,20 @@
                         return;
                     }
 
-                    let value = this.input.value;
-                    if (this.match_current_word) {
-                        value = u.getCurrentWord(this.input);
-                    } 
-
                     const list = typeof this._list === "function" ? this._list() : this._list;
-                    if (list.length > 0 && (
-                                (value.length >= this.min_chars) ||
-                                (this.trigger_on_at && ev.keyCode === value.startsWith('@'))
-                            )) {
+                    if (list.length === 0) {
+                        return;
+                    }
 
+                    let value = this.match_current_word ? u.getCurrentWord(this.input) : this.input.value;
+                        
+                    let ignore_min_chars = false;
+                    if (this.trigger_on_at && value.startsWith('@')) {
+                        ignore_min_chars = true;
+                        value = value.slice('1');
+                    }
+                    
+                    if ((value.length >= this.min_chars) || ignore_min_chars) {
                         this.index = -1;
                         // Populate list with options that match
                         this.ul.innerHTML = "";
@@ -402,19 +397,6 @@
                     }
                 },
 
-                fire (target, type, properties) {
-                    const evt = document.createEvent("HTMLEvents");
-                    evt.initEvent(type, true, true );
-
-                    for (var j in properties) {
-                        if (!Object.prototype.hasOwnProperty.call(properties, j)) {
-                            continue;
-                        }
-                        evt[j] = properties[j];
-                    }
-                    return target.dispatchEvent(evt);
-                },
-
                 regExpEscape (s) {
                     return s.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&");
                 }

+ 2 - 1
src/utils/core.js

@@ -825,7 +825,8 @@
         const cursor = input.selectionEnd || undefined,
               current_word = _.last(input.value.slice(0, cursor).split(' ')),
               value = input.value;
-        input.value = value.slice(0, cursor - current_word.length) + new_value + value.slice(cursor);
+        input.value = value.slice(0, cursor - current_word.length) + `${new_value} ` + value.slice(cursor);
+        input.selectionEnd = cursor - current_word.length + new_value.length + 1;
     };
 
     u.isVisible = function (el) {