/*!
* jQuery UI Autocomplete 1.12.0
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Autocomplete
//>>group: Widgets
//>>description: Lists suggested words as the user is typing.
//>>docs: http://api.jqueryui.com/autocomplete/
//>>demos: http://jqueryui.com/autocomplete/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/autocomplete.css
//>>css.theme: ../../themes/base/theme.css
$.widget("ui.autocomplete", {
\t version: "1.12.0",
\t defaultElement: "<input>",
\t options: {
\t \t appendTo: null,
\t \t autoFocus: false,
\t \t delay: 300,
\t \t minLength: 1,
\t \t position: {
\t \t \t my: "left top",
\t \t \t at: "left bottom",
\t \t \t collision: "none"
\t \t },
\t \t source: null,
\t \t // Callbacks
\t \t change: null,
\t \t close: null,
\t \t focus: null,
\t \t open: null,
\t \t response: null,
\t \t search: null,
\t \t select: null
\t },
\t requestIndex: 0,
\t pending: 0,
\t _create: function() {
\t \t // Some browsers only repeat keydown events, not keypress events,
\t \t // so we use the suppressKeyPress flag to determine if we've already
\t \t // handled the keydown event. #7269
\t \t // Unfortunately the code for & in keypress is the same as the up arrow,
\t \t // so we use the suppressKeyPressRepeat flag to avoid handling keypress
\t \t // events when we know the keydown event was used to modify the
\t \t // search term. #7799
\t \t var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
\t \t \t nodeName = this.element[ 0 ].nodeName.toLowerCase(),
\t \t \t isTextarea = nodeName === "textarea",
\t \t \t isInput = nodeName === "input";
\t \t // Textareas are always multi-line
\t \t // Inputs are always single-line, even if inside a contentEditable element
\t \t // IE also treats inputs as contentEditable
\t \t // All other element types are determined by whether or not they're contentEditable
\t \t this.isMultiLine = isTextarea || !isInput && this._isContentEditable(this.element);
\t \t this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
\t \t this.isNewMenu = true;
\t \t this._addClass("ui-autocomplete-input");
\t \t this.element.attr("autocomplete", "off");
\t \t this._on(this.element, {
\t \t \t keydown: function(event) {
\t \t \t \t if (this.element.prop("readOnly")) {
\t \t \t \t \t suppressKeyPress = true;
\t \t \t \t \t suppressInput = true;
\t \t \t \t \t suppressKeyPressRepeat = true;
\t \t \t \t \t return;
\t \t \t \t }
\t \t \t \t suppressKeyPress = false;
\t \t \t \t suppressInput = false;
\t \t \t \t suppressKeyPressRepeat = false;
\t \t \t \t var keyCode = $.ui.keyCode;
\t \t \t \t switch (event.keyCode) {
\t \t \t \t case keyCode.PAGE_UP:
\t \t \t \t \t suppressKeyPress = true;
\t \t \t \t \t this._move("previousPage", event);
\t \t \t \t \t break;
\t \t \t \t case keyCode.PAGE_DOWN:
\t \t \t \t \t suppressKeyPress = true;
\t \t \t \t \t this._move("nextPage", event);
\t \t \t \t \t break;
\t \t \t \t case keyCode.UP:
\t \t \t \t \t suppressKeyPress = true;
\t \t \t \t \t this._keyEvent("previous", event);
\t \t \t \t \t break;
\t \t \t \t case keyCode.DOWN:
\t \t \t \t \t suppressKeyPress = true;
\t \t \t \t \t this._keyEvent("next", event);
\t \t \t \t \t break;
\t \t \t \t case keyCode.ENTER:
\t \t \t \t \t // when menu is open and has focus
\t \t \t \t \t if (this.menu.active) {
\t \t \t \t \t \t // #6055 - Opera still allows the keypress to occur
\t \t \t \t \t \t // which causes forms to submit
\t \t \t \t \t \t suppressKeyPress = true;
\t \t \t \t \t \t event.preventDefault();
\t \t \t \t \t \t this.menu.select(event);
\t \t \t \t \t }
\t \t \t \t \t break;
\t \t \t \t case keyCode.TAB:
\t \t \t \t \t if (this.menu.active) {
\t \t \t \t \t \t this.menu.select(event);
\t \t \t \t \t }
\t \t \t \t \t break;
\t \t \t \t case keyCode.ESCAPE:
\t \t \t \t \t if (this.menu.element.is(":visible")) {
\t \t \t \t \t \t if (!this.isMultiLine) {
\t \t \t \t \t \t \t this._value(this.term);
\t \t \t \t \t \t }
\t \t \t \t \t \t this.close(event);
\t \t \t \t \t \t // Different browsers have different default behavior for escape
\t \t \t \t \t \t // Single press can mean undo or clear
\t \t \t \t \t \t // Double press in IE means clear the whole form
\t \t \t \t \t \t event.preventDefault();
\t \t \t \t \t }
\t \t \t \t \t break;
\t \t \t \t default:
\t \t \t \t \t suppressKeyPressRepeat = true;
\t \t \t \t \t // search timeout should be triggered before the input value is changed
\t \t \t \t \t this._searchTimeout(event);
\t \t \t \t \t break;
\t \t \t \t }
\t \t \t },
\t \t \t keypress: function(event) {
\t \t \t \t if (suppressKeyPress) {
\t \t \t \t \t suppressKeyPress = false;
\t \t \t \t \t if (!this.isMultiLine || this.menu.element.is(":visible")) {
\t \t \t \t \t \t event.preventDefault();
\t \t \t \t \t }
\t \t \t \t \t return;
\t \t \t \t }
\t \t \t \t if (suppressKeyPressRepeat) {
\t \t \t \t \t return;
\t \t \t \t }
\t \t \t \t // Replicate some key handlers to allow them to repeat in Firefox and Opera
\t \t \t \t var keyCode = $.ui.keyCode;
\t \t \t \t switch (event.keyCode) {
\t \t \t \t case keyCode.PAGE_UP:
\t \t \t \t \t this._move("previousPage", event);
\t \t \t \t \t break;
\t \t \t \t case keyCode.PAGE_DOWN:
\t \t \t \t \t this._move("nextPage", event);
\t \t \t \t \t break;
\t \t \t \t case keyCode.UP:
\t \t \t \t \t this._keyEvent("previous", event);
\t \t \t \t \t break;
\t \t \t \t case keyCode.DOWN:
\t \t \t \t \t this._keyEvent("next", event);
\t \t \t \t \t break;
\t \t \t \t }
\t \t \t },
\t \t \t input: function(event) {
\t \t \t \t if (suppressInput) {
\t \t \t \t \t suppressInput = false;
\t \t \t \t \t event.preventDefault();
\t \t \t \t \t return;
\t \t \t \t }
\t \t \t \t this._searchTimeout(event);
\t \t \t },
\t \t \t focus: function() {
\t \t \t \t this.selectedItem = null;
\t \t \t \t this.previous = this._value();
\t \t \t },
\t \t \t blur: function(event) {
\t \t \t \t if (this.cancelBlur) {
\t \t \t \t \t delete this.cancelBlur;
\t \t \t \t \t return;
\t \t \t \t }
\t \t \t \t clearTimeout(this.searching);
\t \t \t \t this.close(event);
\t \t \t \t this._change(event);
\t \t \t }
\t \t });
\t \t this._initSource();
\t \t this.menu = $("<ul>")
\t \t \t .appendTo(this._appendTo())
\t \t \t .menu({
\t \t \t \t // disable ARIA support, the live region takes care of that
\t \t \t \t role: null
\t \t \t })
\t \t \t .hide()
\t \t \t .menu("instance");
\t \t this._addClass(this.menu.element, "ui-autocomplete", "ui-front");
\t \t this._on(this.menu.element, {
\t \t \t mousedown: function(event) {
\t \t \t \t // prevent moving focus out of the text field
\t \t \t \t event.preventDefault();
\t \t \t \t // IE doesn't prevent moving focus even with event.preventDefault()
\t \t \t \t // so we set a flag to know when we should ignore the blur event
\t \t \t \t this.cancelBlur = true;
\t \t \t \t this._delay(function() {
\t \t \t \t \t delete this.cancelBlur;
\t \t \t \t \t // Support: IE 8 only
\t \t \t \t \t // Right clicking a menu item or selecting text from the menu items will
\t \t \t \t \t // result in focus moving out of the input. However, we've already received
\t \t \t \t \t // and ignored the blur event because of the cancelBlur flag set above. So
\t \t \t \t \t // we restore focus to ensure that the menu closes properly based on the user's
\t \t \t \t \t // next actions.
\t \t \t \t \t if (this.element[ 0 ] !== $.ui.safeActiveElement(this.document[ 0 ])) {
\t \t \t \t \t \t this.element.trigger("focus");
\t \t \t \t \t }
\t \t \t \t });
\t \t \t },
\t \t \t menufocus: function(event, ui) {
\t \t \t \t var label, item;
\t \t \t \t // support: Firefox
\t \t \t \t // Prevent accidental activation of menu items in Firefox (#7024 #9118)
\t \t \t \t if (this.isNewMenu) {
\t \t \t \t \t this.isNewMenu = false;
\t \t \t \t \t if (event.originalEvent && /^mouse/.test(event.originalEvent.type)) {
\t \t \t \t \t \t this.menu.blur();
\t \t \t \t \t \t this.document.one("mousemove", function() {
\t \t \t \t \t \t \t $(event.target).trigger(event.originalEvent);
\t \t \t \t \t \t });
\t \t \t \t \t \t return;
\t \t \t \t \t }
\t \t \t \t }
\t \t \t \t item = ui.item.data("ui-autocomplete-item");
\t \t \t \t if (false !== this._trigger("focus", event, { item: item })) {
\t \t \t \t \t // use value to match what will end up in the input, if it was a key event
\t \t \t \t \t if (event.originalEvent && /^key/.test(event.originalEvent.type)) {
\t \t \t \t \t \t this._value(item.value);
\t \t \t \t \t }
\t \t \t \t }
\t \t \t \t // Announce the value in the liveRegion
\t \t \t \t label = ui.item.attr("aria-label") || item.value;
\t \t \t \t if (label && $.trim(label).length) {
\t \t \t \t \t this.liveRegion.children().hide();
\t \t \t \t \t $("<div>").text(label).appendTo(this.liveRegion);
\t \t \t \t }
\t \t \t },
\t \t \t menuselect: function(event, ui) {
\t \t \t \t var item = ui.item.data("ui-autocomplete-item"),
\t \t \t \t \t previous = this.previous;
\t \t \t \t // Only trigger when focus was lost (click on menu)
\t \t \t \t if (this.element[ 0 ] !== $.ui.safeActiveElement(this.document[ 0 ])) {
\t \t \t \t \t this.element.trigger("focus");
\t \t \t \t \t this.previous = previous;
\t \t \t \t \t // #6109 - IE triggers two focus events and the second
\t \t \t \t \t // is asynchronous, so we need to reset the previous
\t \t \t \t \t // term synchronously and asynchronously :-(
\t \t \t \t \t this._delay(function() {
\t \t \t \t \t \t this.previous = previous;
\t \t \t \t \t \t this.selectedItem = item;
\t \t \t \t \t });
\t \t \t \t }
\t \t \t \t if (false !== this._trigger("select", event, { item: item })) {
\t \t \t \t \t this._value(item.value);
\t \t \t \t }
\t \t \t \t // reset the term after the select event
\t \t \t \t // this allows custom select handling to work properly
\t \t \t \t this.term = this._value();
\t \t \t \t this.close(event);
\t \t \t \t this.selectedItem = item;
\t \t \t }
\t \t });
\t \t this.liveRegion = $("<div>", {
\t \t \t role: "status",
\t \t \t "aria-live": "assertive",
\t \t \t "aria-relevant": "additions"
\t \t })
\t \t \t .appendTo(this.document[ 0 ].body);
\t \t this._addClass(this.liveRegion, null, "ui-helper-hidden-accessible");
\t \t // Turning off autocomplete prevents the browser from remembering the
\t \t // value when navigating through history, so we re-enable autocomplete
\t \t // if the page is unloaded before the widget is destroyed. #7790
\t \t this._on(this.window, {
\t \t \t beforeunload: function() {
\t \t \t \t this.element.removeAttr("autocomplete");
\t \t \t }
\t \t });
\t },
\t _destroy: function() {
\t \t clearTimeout(this.searching);
\t \t this.element.removeAttr("autocomplete");
\t \t this.menu.element.remove();
\t \t this.liveRegion.remove();
\t },
\t _setOption: function(key, value) {
\t \t this._super(key, value);
\t \t if (key === "source") {
\t \t \t this._initSource();
\t \t }
\t \t if (key === "appendTo") {
\t \t \t this.menu.element.appendTo(this._appendTo());
\t \t }
\t \t if (key === "disabled" && value && this.xhr) {
\t \t \t this.xhr.abort();
\t \t }
\t },
\t _isEventTargetInWidget: function(event) {
\t \t var menuElement = this.menu.element[ 0 ];
\t \t return event.target === this.element[ 0 ] ||
\t \t \t event.target === menuElement ||
\t \t \t $.contains(menuElement, event.target);
\t },
\t _closeOnClickOutside: function(event) {
\t \t if (!this._isEventTargetInWidget(event)) {
\t \t \t this.close();
\t \t }
\t },
\t _appendTo: function() {
\t \t var element = this.options.appendTo;
\t \t if (element) {
\t \t \t element = element.jquery || element.nodeType ?
\t \t \t \t $(element) :
\t \t \t \t this.document.find(element).eq(0);
\t \t }
\t \t if (!element || !element[ 0 ]) {
\t \t \t element = this.element.closest(".ui-front, dialog");
\t \t }
\t \t if (!element.length) {
\t \t \t element = this.document[ 0 ].body;
\t \t }
\t \t return element;
\t },
\t _initSource: function() {
\t \t var array, url,
\t \t \t that = this;
\t \t if ($.isArray(this.options.source)) {
\t \t \t array = this.options.source;
\t \t \t this.source = function(request, response) {
\t \t \t \t response($.ui.autocomplete.filter(array, request.term));
\t \t \t };
\t \t } else if (typeof this.options.source === "string") {
\t \t \t url = this.options.source;
\t \t \t this.source = function(request, response) {
\t \t \t \t if (that.xhr) {
\t \t \t \t \t that.xhr.abort();
\t \t \t \t }
\t \t \t \t that.xhr = $.ajax({
\t \t \t \t \t url: url,
\t \t \t \t \t data: request,
\t \t \t \t \t dataType: "json",
\t \t \t \t \t success: function(data) {
\t \t \t \t \t \t response(data);
\t \t \t \t \t },
\t \t \t \t \t error: function() {
\t \t \t \t \t \t response([]);
\t \t \t \t \t }
\t \t \t \t });
\t \t \t };
\t \t } else {
\t \t \t this.source = this.options.source;
\t \t }
\t },
\t _searchTimeout: function(event) {
\t \t clearTimeout(this.searching);
\t \t this.searching = this._delay(function() {
\t \t \t // Search if the value has changed, or if the user retypes the same value (see #7434)
\t \t \t var equalValues = this.term === this._value(),
\t \t \t \t menuVisible = this.menu.element.is(":visible"),
\t \t \t \t modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
\t \t \t if (!equalValues || (equalValues && !menuVisible && !modifierKey)) {
\t \t \t \t this.selectedItem = null;
\t \t \t \t this.search(null, event);
\t \t \t }
\t \t }, this.options.delay);
\t },
\t search: function(value, event) {
\t \t value = value != null ? value : this._value();
\t \t // Always save the actual value, not the one passed as an argument
\t \t this.term = this._value();
\t \t if (value.length < this.options.minLength) {
\t \t \t return this.close(event);
\t \t }
\t \t if (this._trigger("search", event) === false) {
\t \t \t return;
\t \t }
\t \t return this._search(value);
\t },
\t _search: function(value) {
\t \t this.pending++;
\t \t this._addClass("ui-autocomplete-loading");
\t \t this.cancelSearch = false;
\t \t this.source({ term: value }, this._response());
\t },
\t _response: function() {
\t \t var index = ++this.requestIndex;
\t \t return $.proxy(function(content) {
\t \t \t if (index === this.requestIndex) {
\t \t \t \t this.__response(content);
\t \t \t }
\t \t \t this.pending--;
\t \t \t if (!this.pending) {
\t \t \t \t this._removeClass("ui-autocomplete-loading");
\t \t \t }
\t \t }, this);
\t },
\t __response: function(content) {
\t \t if (content) {
\t \t \t content = this._normalize(content);
\t \t }
\t \t this._trigger("response", null, { content: content });
\t \t if (!this.options.disabled && content && content.length && !this.cancelSearch) {
\t \t \t this._suggest(content);
\t \t \t this._trigger("open");
\t \t } else {
\t \t \t // use ._close() instead of .close() so we don't cancel future searches
\t \t \t this._close();
\t \t }
\t },
\t close: function(event) {
\t \t this.cancelSearch = true;
\t \t this._close(event);
\t },
\t _close: function(event) {
\t \t // Remove the handler that closes the menu on outside clicks
\t \t this._off(this.document, "mousedown");
\t \t if (this.menu.element.is(":visible")) {
\t \t \t this.menu.element.hide();
\t \t \t this.menu.blur();
\t \t \t this.isNewMenu = true;
\t \t \t this._trigger("close", event);
\t \t }
\t },
\t _change: function(event) {
\t \t if (this.previous !== this._value()) {
\t \t \t this._trigger("change", event, { item: this.selectedItem });
\t \t }
\t },
\t _normalize: function(items) {
\t \t // assume all items have the right format when the first item is complete
\t \t if (items.length && items[ 0 ].label && items[ 0 ].value) {
\t \t \t return items;
\t \t }
\t \t return $.map(items, function(item) {
\t \t \t if (typeof item === "string") {
\t \t \t \t return {
\t \t \t \t \t label: item,
\t \t \t \t \t value: item
\t \t \t \t };
\t \t \t }
\t \t \t return $.extend({}, item, {
\t \t \t \t label: item.label || item.value,
\t \t \t \t value: item.value || item.label
\t \t \t });
\t \t });
\t },
\t _suggest: function(items) {
\t \t var ul = this.menu.element.empty();
\t \t this._renderMenu(ul, items);
\t \t this.isNewMenu = true;
\t \t this.menu.refresh();
\t \t // Size and position menu
\t \t ul.show();
\t \t this._resizeMenu();
\t \t ul.position($.extend({
\t \t \t of: this.element
\t \t }, this.options.position));
\t \t if (this.options.autoFocus) {
\t \t \t this.menu.next();
\t \t }
\t \t // Listen for interactions outside of the widget (#6642)
\t \t this._on(this.document, {
\t \t \t mousedown: "_closeOnClickOutside"
\t \t });
\t },
\t _resizeMenu: function() {
\t \t var ul = this.menu.element;
\t \t ul.outerWidth(Math.max(
\t \t \t // Firefox wraps long text (possibly a rounding bug)
\t \t \t // so we add 1px to avoid the wrapping (#7513)
\t \t \t ul.width("").outerWidth() + 1,
\t \t \t this.element.outerWidth()
\t \t));
\t },
\t _renderMenu: function(ul, items) {
\t \t var that = this;
\t \t $.each(items, function(index, item) {
\t \t \t that._renderItemData(ul, item);
\t \t });
\t },
\t _renderItemData: function(ul, item) {
\t \t return this._renderItem(ul, item).data("ui-autocomplete-item", item);
\t },
\t _renderItem: function(ul, item) {
\t \t return $("<li>")
\t \t \t .append($("<div>").text(item.label))
\t \t \t .appendTo(ul);
\t },
\t _move: function(direction, event) {
\t \t if (!this.menu.element.is(":visible")) {
\t \t \t this.search(null, event);
\t \t \t return;
\t \t }
\t \t if (this.menu.isFirstItem() && /^previous/.test(direction) ||
\t \t \t \t this.menu.isLastItem() && /^next/.test(direction)) {
\t \t \t if (!this.isMultiLine) {
\t \t \t \t this._value(this.term);
\t \t \t }
\t \t \t this.menu.blur();
\t \t \t return;
\t \t }
\t \t this.menu[ direction ](event);
\t },
\t widget: function() {
\t \t return this.menu.element;
\t },
\t _value: function() {
\t \t return this.valueMethod.apply(this.element, arguments);
\t },
\t _keyEvent: function(keyEvent, event) {
\t \t if (!this.isMultiLine || this.menu.element.is(":visible")) {
\t \t \t this._move(keyEvent, event);
\t \t \t // Prevents moving cursor to beginning/end of the text field in some browsers
\t \t \t event.preventDefault();
\t \t }
\t },
\t // Support: Chrome <=50
\t // We should be able to just use this.element.prop("isContentEditable")
\t // but hidden elements always report false in Chrome.
\t // https://code.google.com/p/chromium/issues/detail?id=313082
\t _isContentEditable: function(element) {
\t \t if (!element.length) {
\t \t \t return false;
\t \t }
\t \t var editable = element.prop("contentEditable");
\t \t if (editable === "inherit") {
\t \t return this._isContentEditable(element.parent());
\t \t }
\t \t return editable === "true";
\t }
});
$.extend($.ui.autocomplete, {
\t escapeRegex: function(value) {
\t \t return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
\t },
\t filter: function(array, term) {
\t \t var matcher = new RegExp($.ui.autocomplete.escapeRegex(term), "i");
\t \t return $.grep(array, function(value) {
\t \t \t return matcher.test(value.label || value.value || value);
\t \t });
\t }
});
// Live region extension, adding a `messages` option
// NOTE: This is an experimental API. We are still investigating
// a full solution for string manipulation and internationalization.
$.widget("ui.autocomplete", $.ui.autocomplete, {
\t options: {
\t \t messages: {
\t \t \t noResults: "No search results.",
\t \t \t results: function(amount) {
\t \t \t \t return amount + (amount > 1 ? " results are" : " result is") +
\t \t \t \t \t " available, use up and down arrow keys to navigate.";
\t \t \t }
\t \t }
\t },
\t __response: function(content) {
\t \t var message;
\t \t this._superApply(arguments);
\t \t if (this.options.disabled || this.cancelSearch) {
\t \t \t return;
\t \t }
\t \t if (content && content.length) {
\t \t \t message = this.options.messages.results(content.length);
\t \t } else {
\t \t \t message = this.options.messages.noResults;
\t \t }
\t \t this.liveRegion.children().hide();
\t \t $("<div>").text(message).appendTo(this.liveRegion);
\t }
});
var widgetsAutocomplete = $.ui.autocomplete;
您是否嘗試使用de在服務器上調試您的代碼veloper工具? AJAX調用是否返回成功?您的網址可能是問題。 – lunaks
@ lunaks - 這是問題,沒有沒有ajax被觸發,當我輸入時沒有觸發......但本地工作沒有任何問題。 –
我嘗試調試但我找不到您的腳本。 (編輯:我的壞,我發現它) – lunaks