选项卡导航不适用于Mozilla Firefox上的自动填充文本框

时间:2015-07-07 12:00:13

标签: javascript jquery jquery-ui firefox

我正在使用' jquery.ui.autocomplete.js'。我面临的问题是,在TAB Press期间,默认Naviagtion卡住了 当它到达自动填充文本框时。该问题仅反映在Mozilla Firefox中。我想要的是在TAB按键上 它将移动到下一个元素。有人可以帮我解决这个问题吗?

我尝试过Googled解决方案,但无法修复。我发布一些链接希望它能帮助你理解isue。 1. http://bugs.jqueryui.com/ticket/6661

我认为问题出在以下几个方面:

        case keyCode.ENTER:
        case keyCode.NUMPAD_ENTER:
            // when menu is open or has focus
            if (self.menu.element.is(":visible")) {
                event.preventDefault();
            }
            //passthrough - ENTER and TAB both select the current element
        case keyCode.TAB:
            if (!self.menu.active) {
                return;
            }
            self.menu.select(event);
            break;
        case keyCode.ESCAPE:
            self.element.val(self.term);
            self.close(event);
            break;
        default:
            // keypress is triggered before the input value is changed
            clearTimeout(self.searching);
            self.searching = setTimeout(function () {
                // only search if the value has changed
                if (self.term != self.element.val()) {
                    self.selectedItem = null;
                    self.search(null, event);
                }
            }, self.options.delay);
            break;
    }
})

我的jquery代码在这里:

(function ($, undefined) {

    $.widget("ui.autocomplete", {
        options: {
            appendTo: "body",
            delay: 300,
            minLength: 1,
            position: {
                my: "left top",
                at: "left bottom",
                collision: "none"
            },
            source: null
        },
        _create: function () {
            var self = this,
            doc = this.element[0].ownerDocument;
            this.element
            .addClass("ui-autocomplete-input")
            .attr("autocomplete", "off")
            // TODO verify these actually work as intended
            .attr({
                role: "textbox",
                "aria-autocomplete": "list",
                "aria-haspopup": "true"
            })
            .bind("keydown.autocomplete", function (event) {
                if (self.options.disabled || self.element.attr("readonly")) {
                    return;
                }

                var keyCode = $.ui.keyCode;
                switch (event.keyCode) {
                    case keyCode.PAGE_UP:
                        self._move("previousPage", event);
                        break;
                    case keyCode.PAGE_DOWN:
                        self._move("nextPage", event);
                        break;
                    case keyCode.UP:
                        self._move("previous", event);
                        // prevent moving cursor to beginning of text field in some browsers
                        event.preventDefault();
                        break;
                    case keyCode.DOWN:
                        self._move("next", event);
                        // prevent moving cursor to end of text field in some browsers
                        event.preventDefault();
                        break;
                    case keyCode.ENTER:
                    case keyCode.NUMPAD_ENTER:
                        // when menu is open or has focus
                        if (self.menu.element.is(":visible")) {
                            event.preventDefault();
                        }
                        //passthrough - ENTER and TAB both select the current element
                    case keyCode.TAB:
                        if (!self.menu.active) {
                            return;
                        }
                        self.menu.select(event);
                        break;
                    case keyCode.ESCAPE:
                        self.element.val(self.term);
                        self.close(event);
                        break;
                    default:
                        // keypress is triggered before the input value is changed
                        clearTimeout(self.searching);
                        self.searching = setTimeout(function () {
                            // only search if the value has changed
                            if (self.term != self.element.val()) {
                                self.selectedItem = null;
                                self.search(null, event);
                            }
                        }, self.options.delay);
                        break;
                }
            })

            .bind("focus.autocomplete", function () {
                if (self.options.disabled) {
                    return;
                }

                self.selectedItem = null;
                self.previous = self.element.val();
            })
        .bind("blur.autocomplete", function (event) {
            if (self.options.disabled) {
                return;
            }

            clearTimeout(self.searching);
            // clicks on the menu (or a button to trigger a search) will cause a blur event
            self.closing = setTimeout(function () {
                self.close(event);
                self._change(event);
            }, 150);
        });
            this._initSource();
            this.response = function () {
                return self._response.apply(self, arguments);
            };
            this.menu = $("<ul></ul>")
            .addClass("ui-autocomplete")
            .appendTo($(this.options.appendTo || "body", doc)[0])
            // prevent the close-on-blur in case of a "slow" click on the menu (long mousedown)
            .mousedown(function (event) {
                // clicking on the scrollbar causes focus to shift to the body
                // but we can't detect a mouseup or a click immediately afterward
                // so we have to track the next mousedown and close the menu if
                // the user clicks somewhere outside of the autocomplete
                var menuElement = self.menu.element[0];
                if (event.target === menuElement) {
                    setTimeout(function () {
                        $(document).one('mousedown', function (event) {
                            if (event.target !== self.element[0] &&
                                event.target !== menuElement &&
                                !$.ui.contains(menuElement, event.target)) {
                                self.close();
                            }
                        });
                    }, 1);
                }

                // use another timeout to make sure the blur-event-handler on the input was already triggered
                setTimeout(function () {
                    clearTimeout(self.closing);
                }, 13);
            })
            .menu({
                focus: function (event, ui) {
                    var item = ui.item.data("item.autocomplete");
                    if (false !== self._trigger("focus", null, { item: item })) {
                        // use value to match what will end up in the input, if it was a key event
                        if (/^key/.test(event.originalEvent.type)) {
                            self.element.val(item.value);
                        }
                    }
                },
                selected: function (event, ui) {
                    var item = ui.item.data("item.autocomplete"),
                        previous = self.previous;

                    // only trigger when focus was lost (click on menu)
                    if (self.element[0] !== doc.activeElement) {
                        self.element.focus();
                        self.previous = previous;
                    }

                    if (false !== self._trigger("select", event, { item: item })) {
                        self.element.val(item.value);
                    }

                    self.close(event);
                    self.selectedItem = item;
                },
                blur: function (event, ui) {
                    // don't set the value of the text field if it's already correct
                    // this prevents moving the cursor unnecessarily
                    if (self.menu.element.is(":visible") &&
                        (self.element.val() !== self.term)) {
                        self.element.val(self.term);
                    }
                }
            })
            .zIndex(this.element.zIndex() + 1)
            // workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781
            .css({ top: 0, left: 0 })
            .hide()
            .data("menu");
            if ($.fn.bgiframe) {
                this.menu.element.bgiframe();
            }
        },

        destroy: function () {
            this.element
            .removeClass("ui-autocomplete-input")
            .removeAttr("autocomplete")
            .removeAttr("role")
            .removeAttr("aria-autocomplete")
            .removeAttr("aria-haspopup");
            this.menu.element.remove();
            $.Widget.prototype.destroy.call(this);
        },

        _setOption: function (key, value) {
            $.Widget.prototype._setOption.apply(this, arguments);
            if (key === "source") {
                this._initSource();
            }
            if (key === "appendTo") {
                this.menu.element.appendTo($(value || "body", this.element[0].ownerDocument)[0])
            }
        },

        _initSource: function () {
            var array,
            url;
            if ($.isArray(this.options.source)) {
                array = this.options.source;
                this.source = function (request, response) {
                    response($.ui.autocomplete.filter(array, request.term));
                };
            } else if (typeof this.options.source === "string") {
                url = this.options.source;
                this.source = function (request, response) {
                    $.getJSON(url, request, response);
                };
            } else {
                this.source = this.options.source;
            }
        },

        search: function (value, event) {
            value = value != null ? value : this.element.val();
            if (value.length < this.options.minLength) {
                return this.close(event);
            }

            clearTimeout(this.closing);
            if (this._trigger("search") === false) {
                return;
            }

            return this._search(value);
        },

        _search: function (value) {
            this.term = this.element
            .addClass("ui-autocomplete-loading")
            // always save the actual value, not the one passed as an argument
            .val();

            this.source({ term: value }, this.response);
        },

        _response: function (content) {
            if (content.length) {
                content = this._normalize(content);
                this._suggest(content);
                this._trigger("open");
            } else {
                this.close();
            }
            this.element.removeClass("ui-autocomplete-loading");
        },

        close: function (event) {
            clearTimeout(this.closing);
            if (this.menu.element.is(":visible")) {
                this._trigger("close", event);
                this.menu.element.hide();
                this.menu.deactivate();
            }
        },

        _change: function (event) {
            if (this.previous !== this.element.val()) {
                this._trigger("change", event, { item: this.selectedItem });
            }
        },

        _normalize: function (items) {
            // assume all items have the right format when the first item is complete
            if (items.length && items[0].label && items[0].value) {
                return items;
            }
            return $.map(items, function (item) {
                if (typeof item === "string") {
                    return {
                        label: item,
                        value: item
                    };
                }
                return $.extend({
                    label: item.label || item.value,
                    value: item.value || item.label
                }, item);
            });
        },

        _suggest: function (items) {
            var ul = this.menu.element
                .empty()
                .zIndex(this.element.zIndex() + 1),
            menuWidth,
            textWidth;
            this._renderMenu(ul, items);
            // TODO refresh should check if the active item is still in the dom, removing the need for a manual deactivate
            this.menu.deactivate();
            this.menu.refresh();
            this.menu.element.show().position($.extend({
                of: this.element
            }, this.options.position));

            menuWidth = ul.width("").outerWidth();
            textWidth = this.element.outerWidth();
            ul.outerWidth(Math.max(menuWidth, textWidth));
        },

        _renderMenu: function (ul, items) {
            var self = this;
            $.each(items, function (index, item) {
                self._renderItem(ul, item);
            });
        },

        _renderItem: function (ul, item) {
            return $("<li></li>")
            .data("item.autocomplete", item)
            .append($("<a></a>").text(item.label))
            .appendTo(ul);
        },

        _move: function (direction, event) {
            if (!this.menu.element.is(":visible")) {
                this.search(null, event);
                return;
            }
            if (this.menu.first() && /^previous/.test(direction) ||
                this.menu.last() && /^next/.test(direction)) {
                this.element.val(this.term);
                this.menu.deactivate();
                return;
            }
            this.menu[direction](event);
        },

        widget: function () {
            return this.menu.element;
        }
    });

    $.extend($.ui.autocomplete, {
        escapeRegex: function (value) {
            return value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
        },
        filter: function (array, term) {
            var matcher = new RegExp($.ui.autocomplete.escapeRegex(term), "i");
            return $.grep(array, function (value) {
                return matcher.test(value.label || value.value || value);
            });
        }
    });

} (jQuery));

1 个答案:

答案 0 :(得分:0)

是的,您链接到的错误提示会显示您need to follow的变更集。

请注意,而不是说$('selector').autocomplete(...)您应该这样做:

$('selector').bind('keydown', function (event) {
  if (event.keyCode === $.ui.keyCode.TAB &&
      $(this).data('autocomplete').menu.active ) {

    event.preventDefault();
  }
}).autocomplete(...)

请注意,如果菜单处于“活动状态”,您正在拦截TAB键盘,并阻止事件执行默认行为,而在浏览器中,该行为正在关注下一个静态布局的元素。