From 378559ff47250fa44c1dbbc755d2dba550a63f2a Mon Sep 17 00:00:00 2001 From: evazion Date: Wed, 13 Nov 2019 01:39:03 -0600 Subject: [PATCH] autocomplete: make number of results configurable (partly). Add `Danbooru.Autocomplete.MAX_RESULTS` param that controls the number of results returned by autocomplete. This does not work with tag autocomplete for Builders. Builder autocomplete still needs to be refactored and unified with Member autocomplete. Also fix a bug in the /saved_searches/labels endpoint where the limit param wasn't respected. --- app/controllers/saved_searches_controller.rb | 2 +- app/controllers/tags_controller.rb | 2 +- .../src/javascripts/autocomplete.js.erb | 16 +++++++++------- app/models/tag.rb | 10 +++++----- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/app/controllers/saved_searches_controller.rb b/app/controllers/saved_searches_controller.rb index de0733e90..716d21d73 100644 --- a/app/controllers/saved_searches_controller.rb +++ b/app/controllers/saved_searches_controller.rb @@ -7,7 +7,7 @@ class SavedSearchesController < ApplicationController end def labels - @labels = SavedSearch.search_labels(CurrentUser.id, params[:search]) + @labels = SavedSearch.search_labels(CurrentUser.id, params[:search]).take(params[:limit].to_i || 10) respond_with(@labels) end diff --git a/app/controllers/tags_controller.rb b/app/controllers/tags_controller.rb index c4243db00..d919bf98b 100644 --- a/app/controllers/tags_controller.rb +++ b/app/controllers/tags_controller.rb @@ -18,7 +18,7 @@ class TagsController < ApplicationController # limit rollout @tags = TagAutocomplete.search(params[:search][:name_matches]) else - @tags = Tag.names_matches_with_aliases(params[:search][:name_matches]) + @tags = Tag.names_matches_with_aliases(params[:search][:name_matches], limit: params[:limit]) end # XXX diff --git a/app/javascript/src/javascripts/autocomplete.js.erb b/app/javascript/src/javascripts/autocomplete.js.erb index 8c8b62641..4331080ba 100644 --- a/app/javascript/src/javascripts/autocomplete.js.erb +++ b/app/javascript/src/javascripts/autocomplete.js.erb @@ -11,6 +11,7 @@ Autocomplete.ORDER_METATAGS = <%= Tag::ORDER_METATAGS.to_json.html_safe %>; Autocomplete.TAG_PREFIXES = "-|~|" + Object.keys(Autocomplete.TAG_CATEGORIES).map(category => category + ":").join("|"); Autocomplete.METATAGS_REGEX = Autocomplete.METATAGS.concat(Object.keys(Autocomplete.TAG_CATEGORIES)).join("|"); Autocomplete.TERM_REGEX = new RegExp(`([-~]*)(?:(${Autocomplete.METATAGS_REGEX}):)?(\\S*)$`, "i"); +Autocomplete.MAX_RESULTS = 10; Autocomplete.initialize_all = function() { if (CurrentUser.data("enable-auto-complete")) { @@ -288,7 +289,7 @@ Autocomplete.static_metatag_source = function(term, metatag) { var sub_metatags = this.static_metatags[metatag]; var matches = sub_metatags.filter(sub_metatag => sub_metatag.startsWith(term.toLowerCase())); - matches = matches.map(sub_metatag => `${metatag}:${sub_metatag}`).sort().slice(0, 10); + matches = matches.map(sub_metatag => `${metatag}:${sub_metatag}`).sort().slice(0, Autocomplete.MAX_RESULTS); return matches; } @@ -300,6 +301,7 @@ Autocomplete.tag_source = async function(term) { let tags = await $.getJSON("/tags/autocomplete", { "search[name_matches]": term, + "limit": Autocomplete.MAX_RESULTS, "expiry": 7 }); @@ -322,7 +324,7 @@ Autocomplete.artist_source = async function(term) { "search[name_like]": term.trim().replace(/\s+/g, "_") + "*", "search[is_active]": true, "search[order]": "post_count", - "limit": 10, + "limit": Autocomplete.MAX_RESULTS, "expiry": 7 }); @@ -341,7 +343,7 @@ Autocomplete.wiki_source = async function(term) { "search[title]": term + "*", "search[hide_deleted]": "Yes", "search[order]": "post_count", - "limit": 10, + "limit": Autocomplete.MAX_RESULTS, "expiry": 7 }); @@ -360,7 +362,7 @@ Autocomplete.user_source = async function(term, prefix = "") { "search[order]": "post_upload_count", "search[current_user_first]": "true", "search[name_matches]": term + "*", - "limit": 10 + "limit": Autocomplete.MAX_RESULTS }); return users.map(function(user) { @@ -378,7 +380,7 @@ Autocomplete.pool_source = async function(term, prefix = "") { "search[name_matches]": term, "search[is_deleted]": false, "search[order]": "post_count", - "limit": 10 + "limit": Autocomplete.MAX_RESULTS }); return pools.map(function(pool) { @@ -395,7 +397,7 @@ Autocomplete.pool_source = async function(term, prefix = "") { Autocomplete.favorite_group_source = async function(term, prefix = "") { let favgroups = await $.getJSON("/favorite_groups", { "search[name_matches]": term, - "limit": 10 + "limit": Autocomplete.MAX_RESULTS }); return favgroups.map(function(favgroup) { @@ -410,7 +412,7 @@ Autocomplete.favorite_group_source = async function(term, prefix = "") { Autocomplete.saved_search_source = async function(term, prefix = "") { let labels = await $.getJSON("/saved_searches/labels", { "search[label]": term + "*", - "limit": 10 + "limit": Autocomplete.MAX_RESULTS }); return labels.map(function(label) { diff --git a/app/models/tag.rb b/app/models/tag.rb index 8af8d375f..4cc58717b 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -895,12 +895,12 @@ class Tag < ApplicationRecord q end - def names_matches_with_aliases(name) + def names_matches_with_aliases(name, limit: 10) name = normalize_name(name) wildcard_name = name + '*' query1 = Tag.select("tags.name, tags.post_count, tags.category, null AS antecedent_name") - .search(:name_matches => wildcard_name, :order => "count").limit(10) + .search(:name_matches => wildcard_name, :order => "count").limit(limit) query2 = TagAlias.select("tags.name, tags.post_count, tags.category, tag_aliases.antecedent_name") .joins("INNER JOIN tags ON tags.name = tag_aliases.consequent_name") @@ -909,13 +909,13 @@ class Tag < ApplicationRecord .where("tags.name NOT LIKE ? ESCAPE E'\\\\'", wildcard_name.to_escaped_for_sql_like) .where("tag_aliases.post_count > 0") .order("tag_aliases.post_count desc") - .limit(20) # Get 20 records even though only 10 will be displayed in case some duplicates get filtered out. + .limit(limit * 2) # Get extra records in case some duplicates get filtered out. sql_query = "((#{query1.to_sql}) UNION ALL (#{query2.to_sql})) AS unioned_query" - tags = Tag.select("DISTINCT ON (name, post_count) *").from(sql_query).order("post_count desc").limit(10) + tags = Tag.select("DISTINCT ON (name, post_count) *").from(sql_query).order("post_count desc").limit(limit) if tags.empty? - tags = Tag.select("tags.name, tags.post_count, tags.category, null AS antecedent_name").fuzzy_name_matches(name).order_similarity(name).nonempty.limit(10) + tags = Tag.select("tags.name, tags.post_count, tags.category, null AS antecedent_name").fuzzy_name_matches(name).order_similarity(name).nonempty.limit(limit) end tags