This option was originally added in issue #1747. But only ~350 users ever disabled autocomplete, only ~120 of these were seen in the last year, and only 9 new users who signed up in the last year disabled it. Users wishing to disable autocomplete can use this CSS: .ui-autocomplete { display: none !important: } or this Javascript: $("[data-autocomplete]").autocomplete("disable");
215 lines
6.8 KiB
Plaintext
215 lines
6.8 KiB
Plaintext
import CurrentUser from './current_user'
|
|
|
|
let Autocomplete = {};
|
|
|
|
/* eslint-disable */
|
|
Autocomplete.TAG_CATEGORIES = <%= TagCategory.mapping.to_json.html_safe %>;
|
|
/* eslint-enable */
|
|
|
|
Autocomplete.TAG_PREFIXES = "-|~|" + Object.keys(Autocomplete.TAG_CATEGORIES).map(category => category + ":").join("|");
|
|
Autocomplete.MAX_RESULTS = 10;
|
|
|
|
Autocomplete.initialize_all = function() {
|
|
$.widget("ui.autocomplete", $.ui.autocomplete, {
|
|
options: {
|
|
delay: 0,
|
|
minLength: 1,
|
|
autoFocus: false,
|
|
focus: function() { return false; },
|
|
},
|
|
_create: function() {
|
|
this.element.on("keydown.Autocomplete.tab", null, "tab", Autocomplete.on_tab);
|
|
this._super();
|
|
},
|
|
_renderItem: Autocomplete.render_item,
|
|
search: function(value, event) {
|
|
if ($(this).data("ui-autocomplete")) {
|
|
$(this).data("ui-autocomplete").menu.bindings = $();
|
|
}
|
|
this._super(value, event);
|
|
},
|
|
});
|
|
|
|
this.initialize_tag_autocomplete();
|
|
this.initialize_mention_autocomplete($("form div.input.dtext textarea"));
|
|
this.initialize_fields($('[data-autocomplete="tag"]'), "tag");
|
|
this.initialize_fields($('[data-autocomplete="artist"]'), "artist");
|
|
this.initialize_fields($('[data-autocomplete="pool"]'), "pool");
|
|
this.initialize_fields($('[data-autocomplete="user"]'), "user");
|
|
this.initialize_fields($('[data-autocomplete="wiki-page"]'), "wiki_page");
|
|
this.initialize_fields($('[data-autocomplete="favorite-group"]'), "favorite_group");
|
|
this.initialize_fields($('[data-autocomplete="saved-search-label"]'), "saved_search_label");
|
|
}
|
|
|
|
Autocomplete.initialize_fields = function($fields, type) {
|
|
$fields.autocomplete({
|
|
source: async function(request, respond) {
|
|
let results = await Autocomplete.autocomplete_source(request.term, type);
|
|
respond(results);
|
|
},
|
|
});
|
|
};
|
|
|
|
Autocomplete.initialize_mention_autocomplete = function($fields) {
|
|
$fields.autocomplete({
|
|
select: function(event, ui) {
|
|
Autocomplete.insert_completion(this, ui.item.value);
|
|
return false;
|
|
},
|
|
source: async function(req, resp) {
|
|
var cursor = this.element.get(0).selectionStart;
|
|
var name = null;
|
|
|
|
for (var i = cursor; i >= 1; --i) {
|
|
if (req.term[i - 1] === " ") {
|
|
return;
|
|
}
|
|
|
|
if (req.term[i - 1] === "@") {
|
|
if (i === 1 || /[ \r\n]/.test(req.term[i - 2])) {
|
|
name = req.term.substring(i, cursor);
|
|
break;
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (name) {
|
|
let results = await Autocomplete.autocomplete_source(name, "mention");
|
|
resp(results);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
Autocomplete.initialize_tag_autocomplete = function() {
|
|
var $fields_multiple = $('[data-autocomplete="tag-query"], [data-autocomplete="tag-edit"]');
|
|
|
|
$fields_multiple.autocomplete({
|
|
select: function(event, ui) {
|
|
// Prevent Upload.initialize_enter_on_tags from running if the
|
|
// Enter key is used to select a tag from the autocomplete menu.
|
|
if (event.key === "Enter") {
|
|
event.stopImmediatePropagation();
|
|
}
|
|
|
|
Autocomplete.insert_completion(this, ui.item.value);
|
|
return false;
|
|
},
|
|
source: async function(req, resp) {
|
|
let term = Autocomplete.current_term(this.element);
|
|
let results = await Autocomplete.autocomplete_source(term, "tag_query");
|
|
resp(results);
|
|
}
|
|
});
|
|
}
|
|
|
|
Autocomplete.current_term = function($input) {
|
|
let query = $input.get(0).value;
|
|
let caret = $input.get(0).selectionStart;
|
|
let match = query.substring(0, caret).match(/\S*$/);
|
|
return match[0];
|
|
};
|
|
|
|
// Update the input field with the item currently focused in the
|
|
// autocomplete menu, then position the caret just after the inserted completion.
|
|
Autocomplete.insert_completion = function(input, completion) {
|
|
// Trim all whitespace (tabs, spaces) except for line returns
|
|
var before_caret_text = input.value.substring(0, input.selectionStart).replace(/^[ \t]+|[ \t]+$/gm, "");
|
|
var after_caret_text = input.value.substring(input.selectionStart).replace(/^[ \t]+|[ \t]+$/gm, "");
|
|
|
|
var regexp = new RegExp("(" + Autocomplete.TAG_PREFIXES + ")?\\S+$", "g");
|
|
before_caret_text = before_caret_text.replace(regexp, "$1") + completion + " ";
|
|
|
|
input.value = before_caret_text + after_caret_text;
|
|
input.selectionStart = input.selectionEnd = before_caret_text.length;
|
|
};
|
|
|
|
// If we press tab while the autocomplete menu is open but nothing is
|
|
// focused, complete the first item and close the menu.
|
|
Autocomplete.on_tab = function(event) {
|
|
var input = this;
|
|
var autocomplete = $(input).autocomplete("instance");
|
|
var $autocomplete_menu = autocomplete.menu.element;
|
|
|
|
if (!$autocomplete_menu.is(":visible")) {
|
|
return;
|
|
}
|
|
|
|
if ($autocomplete_menu.has(".ui-state-active").length === 0) {
|
|
var $first_item = $autocomplete_menu.find(".ui-menu-item").first();
|
|
var completion = $first_item.data().uiAutocompleteItem.value;
|
|
|
|
Autocomplete.insert_completion(input, completion);
|
|
autocomplete.close();
|
|
}
|
|
|
|
// Prevent the tab key from moving focus to the next element.
|
|
event.preventDefault();
|
|
};
|
|
|
|
Autocomplete.render_item = function(list, item) {
|
|
var $link = $("<a/>");
|
|
$link.text(item.label);
|
|
$link.attr("href", "/posts?tags=" + encodeURIComponent(item.value));
|
|
$link.on("click.danbooru", function(e) {
|
|
e.preventDefault();
|
|
});
|
|
|
|
if (item.antecedent) {
|
|
var antecedent = item.antecedent.replace(/_/g, " ");
|
|
var arrow = $("<span/>").html(" → ").addClass("autocomplete-arrow");
|
|
var antecedent_element = $("<span/>").text(antecedent).addClass("autocomplete-antecedent");
|
|
$link.prepend([
|
|
antecedent_element,
|
|
arrow
|
|
]);
|
|
}
|
|
|
|
if (item.post_count !== undefined) {
|
|
var count = item.post_count;
|
|
|
|
if (count >= 1000) {
|
|
count = Math.floor(count / 1000) + "k";
|
|
}
|
|
|
|
var $post_count = $("<span/>").addClass("post-count").css("float", "right").text(count);
|
|
$link.append($post_count);
|
|
}
|
|
|
|
if (/^tag/.test(item.type)) {
|
|
$link.addClass("tag-type-" + item.category);
|
|
} else if (item.type === "user") {
|
|
var level_class = "user-" + item.level.toLowerCase();
|
|
$link.addClass(level_class);
|
|
} else if (item.type === "pool") {
|
|
$link.addClass("pool-category-" + item.category);
|
|
}
|
|
|
|
var $menu_item = $("<div/>").append($link);
|
|
var $list_item = $("<li/>").data("item.autocomplete", item).append($menu_item);
|
|
|
|
var data_attributes = ["type", "antecedent", "value", "category", "post_count"];
|
|
data_attributes.forEach(attr => {
|
|
$list_item.attr(`data-autocomplete-${attr.replace(/_/g, "-")}`, item[attr]);
|
|
});
|
|
|
|
return $list_item.appendTo(list);
|
|
};
|
|
|
|
Autocomplete.autocomplete_source = function(query, type) {
|
|
return $.getJSON("/autocomplete.json", {
|
|
"search[query]": query,
|
|
"search[type]": type,
|
|
"limit": Autocomplete.MAX_RESULTS
|
|
});
|
|
}
|
|
|
|
$(document).ready(function() {
|
|
Autocomplete.initialize_all();
|
|
});
|
|
|
|
export default Autocomplete;
|
|
|