diff --git a/app/controllers/artist_urls_controller.rb b/app/controllers/artist_urls_controller.rb index cd3c97e54..2b2ba419e 100644 --- a/app/controllers/artist_urls_controller.rb +++ b/app/controllers/artist_urls_controller.rb @@ -1,5 +1,5 @@ class ArtistUrlsController < ApplicationController - respond_to :json, :xml, :html + respond_to :js, :json, :xml, :html before_action :member_only, except: [:index] def index diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index 3e9fd8e62..5fca85ba8 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -46,7 +46,6 @@ class PostsController < ApplicationController @post = Post.find(params[:id]) @post.update(post_params) if @post.visible? - save_recent_tags respond_with_post_after_update(@post) end @@ -96,15 +95,6 @@ private params[:tags] || (params[:post] && params[:post][:tags]) end - def save_recent_tags - if @post - tags = Tag.scan_tags(@post.tag_string) - tags = (TagAlias.to_aliased(tags) + Tag.scan_tags(cookies[:recent_tags])).uniq.slice(0, 30) - cookies[:recent_tags] = tags.join(" ") - cookies[:recent_tags_with_categories] = Tag.categories_for(tags).to_a.flatten.join(" ") - end - end - def respond_with_post_after_update(post) respond_with(post) do |format| format.html do diff --git a/app/controllers/related_tags_controller.rb b/app/controllers/related_tags_controller.rb index 8acd30756..438c4f455 100644 --- a/app/controllers/related_tags_controller.rb +++ b/app/controllers/related_tags_controller.rb @@ -1,10 +1,9 @@ class RelatedTagsController < ApplicationController - respond_to :json - respond_to :html, :only=>[:show] + respond_to :json, :xml, :js, :html, except: [:update] before_action :require_reportbooru_key, only: [:update] def show - @query = RelatedTagQuery.new(params[:query].to_s.downcase, params[:category]) + @query = RelatedTagQuery.new(query: params[:query], category: params[:category], user: CurrentUser.user) respond_with(@query) do |format| format.json do render :json => @query.to_json diff --git a/app/controllers/uploads_controller.rb b/app/controllers/uploads_controller.rb index 5af7fa47e..e70bb60e8 100644 --- a/app/controllers/uploads_controller.rb +++ b/app/controllers/uploads_controller.rb @@ -58,21 +58,11 @@ class UploadsController < ApplicationController flash[:notice] = @service.warnings.join(".\n \n") end - save_recent_tags respond_with(@upload) end private - def save_recent_tags - if @upload - tags = Tag.scan_tags(@upload.tag_string) - tags = (TagAlias.to_aliased(tags) + Tag.scan_tags(cookies[:recent_tags])).compact.uniq.slice(0, 30) - cookies[:recent_tags] = tags.join(" ") - cookies[:recent_tags_with_categories] = Tag.categories_for(tags).to_a.flatten.join(" ") - end - end - def upload_params permitted_params = %i[ file source tag_string rating status parent_id artist_commentary_title diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 696006c23..d6c74e2e4 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -66,8 +66,6 @@ class UsersController < ApplicationController @user = User.find(params[:id]) check_privilege(@user) @user.update(user_params(:update)) - cookies.delete(:favorite_tags) - cookies.delete(:favorite_tags_with_categories) if @user.errors.any? flash[:notice] = @user.errors.full_messages.join("; ") else diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js index dd267c07f..51ec8c039 100644 --- a/app/javascript/packs/application.js +++ b/app/javascript/packs/application.js @@ -38,7 +38,7 @@ export { default as Note } from '../src/javascripts/notes.js'; export { default as Post } from '../src/javascripts/posts.js.erb'; export { default as PostModeMenu } from '../src/javascripts/post_mode_menu.js'; export { default as PostTooltip } from '../src/javascripts/post_tooltips.js'; -export { default as RelatedTag } from '../src/javascripts/related_tag.js.erb'; +export { default as RelatedTag } from '../src/javascripts/related_tag.js'; export { default as Shortcuts } from '../src/javascripts/shortcuts.js'; export { default as Upload } from '../src/javascripts/uploads.js'; export { default as Utility } from '../src/javascripts/utility.js'; diff --git a/app/javascript/src/javascripts/posts.js.erb b/app/javascript/src/javascripts/posts.js.erb index 6c8a20de3..9273263d0 100644 --- a/app/javascript/src/javascripts/posts.js.erb +++ b/app/javascript/src/javascripts/posts.js.erb @@ -1,6 +1,5 @@ import Utility from './utility' import Hammer from 'hammerjs' -import RelatedTag from './related_tag.js.erb' import Cookie from './cookie' import Note from './notes' import SavedSearch from './saved_searches' @@ -83,11 +82,6 @@ Post.initialize_edit_dialog = function() { Post.open_edit_dialog(); e.preventDefault(); }); - - $("#toggle-related-tags-link").on("click.danbooru", function(e) { - RelatedTag.toggle(); - e.preventDefault(); - }); } Post.open_edit_dialog = function() { @@ -99,14 +93,11 @@ Post.open_edit_dialog = function() { $("#comments").hide(); $("#post-sections li").removeClass("active"); $("#post-edit-link").parent("li").addClass("active"); - $("#related-tags-container").show(); var $tag_string = $("#post_tag_string,#upload_tag_string"); $("div.input").has($tag_string).prevAll().hide(); $("#open-edit-dialog").hide(); - $("#toggle-related-tags-link").show().click(); - var dialog = $("
").attr("id", "edit-dialog"); $("#form").appendTo(dialog); dialog.dialog({ @@ -158,17 +149,18 @@ Post.open_edit_dialog = function() { $tag_string.css({"resize": "none", "width": "100%"}); $tag_string.focus().selectEnd().height($tag_string[0].scrollHeight); + + $(document).trigger("danbooru:open-post-edit-dialog"); } Post.close_edit_dialog = function(e, ui) { $("#form").appendTo($("#c-posts #edit,#c-uploads #a-new")); $("#edit-dialog").remove(); - RelatedTag.show(); - $("#toggle-related-tags-link").hide(); var $tag_string = $("#post_tag_string,#upload_tag_string"); $("div.input").has($tag_string).prevAll().show(); $("#open-edit-dialog").show(); $tag_string.css({"resize": "", "width": ""}); + $(document).trigger("danbooru:close-post-edit-dialog"); } Post.initialize_similar = function() { @@ -434,9 +426,8 @@ Post.initialize_post_sections = function() { $("#edit").show(); $("#comments").hide(); $("#post_tag_string").focus().selectEnd().height($("#post_tag_string")[0].scrollHeight); - $("#related-tags-button").trigger("click"); - $("#fetch-data-manual").trigger("click"); $("#recommended").hide(); + $(document).trigger("danbooru:open-post-edit-tab"); } else if (e.target.hash === "#recommended") { $("#comments").hide(); $("#edit").hide(); diff --git a/app/javascript/src/javascripts/related_tag.js b/app/javascript/src/javascripts/related_tag.js new file mode 100644 index 000000000..2b34c5d17 --- /dev/null +++ b/app/javascript/src/javascripts/related_tag.js @@ -0,0 +1,148 @@ +import Uploads from './uploads'; +import Utility from './utility'; + +let RelatedTag = {}; + +RelatedTag.initialize_all = function() { + $(document).on("click.danbooru", ".related-tags-button", RelatedTag.on_click_related_tags_button); + $(document).on("click.danbooru", ".related-tags a.search-tag", RelatedTag.toggle_tag); + $(document).on("click.danbooru", "#show-related-tags-link", RelatedTag.show); + $(document).on("click.danbooru", "#hide-related-tags-link", RelatedTag.hide); + $(document).on("keyup.danbooru.relatedTags", "#upload_tag_string, #post_tag_string", RelatedTag.update_selected); + + $(document).on("danbooru:update-source-data", RelatedTag.on_update_source_data); + $(document).on("danbooru:open-post-edit-dialog", RelatedTag.hide); + $(document).on("danbooru:close-post-edit-dialog", RelatedTag.show); + + // Initialize the recent/favorite/translated/artist tag columns once, the first time the related tags are shown. + $(document).one("danbooru:show-related-tags", RelatedTag.initialize_recent_and_favorite_tags); + $(document).one("danbooru:show-related-tags", Uploads.fetch_data_manual); + + // Show the related tags automatically when the "Edit" tab is opened, or by default on the uploads page. + $(document).on("danbooru:open-post-edit-tab", RelatedTag.show); + if ($("#c-uploads #a-new").length) { + RelatedTag.show(); + } +} + +RelatedTag.initialize_recent_and_favorite_tags = function(event) { + $.get("/related_tag.js", { user_tags: true }); +} + +RelatedTag.on_click_related_tags_button = function (event) { + $.get("/related_tag.js", { query: RelatedTag.current_tag(), category: $(event.target).data("category") }); + RelatedTag.show(); +} + +RelatedTag.on_update_source_data = function (event, { related_tags_html }) { + $(".source-related-tags-columns").replaceWith(related_tags_html); + RelatedTag.update_selected(); +} + +RelatedTag.current_tag = function() { + // 1. abc def | -> def + // 2. abc def| -> def + // 3. abc de|f -> def + // 4. abc |def -> def + // 5. abc| def -> abc + // 6. ab|c def -> abc + // 7. |abc def -> abc + // 8. | abc def -> abc + + var $field = $("#upload_tag_string,#post_tag_string"); + var string = $field.val(); + var n = string.length; + var a = $field.prop('selectionStart'); + var b = $field.prop('selectionStart'); + + if ((a > 0) && (a < (n - 1)) && (!/\s/.test(string[a])) && (/\s/.test(string[a - 1]))) { + // 4 is the only case where we need to scan forward. in all other cases we + // can drag a backwards, and then drag b forwards. + + while ((b < n) && (!/\s/.test(string[b]))) { + b++; + } + } else if (string.search(/\S/) > b) { // case 8 + b = string.search(/\S/); + while ((b < n) && (!/\s/.test(string[b]))) { + b++; + } + } else { + while ((a > 0) && ((/\s/.test(string[a])) || (string[a] === undefined))) { + a--; + b--; + } + + while ((a > 0) && (!/\s/.test(string[a - 1]))) { + a--; + b--; + } + + while ((b < (n - 1)) && (!/\s/.test(string[b]))) { + b++; + } + } + + b++; + return string.slice(a, b); +} + +RelatedTag.update_selected = function(e) { + var current_tags = $("#upload_tag_string,#post_tag_string").val().toLowerCase().match(/\S+/g) || []; + var $all_tags = $(".related-tags a.search-tag"); + $all_tags.removeClass("selected"); + + $all_tags.each(function(i, tag) { + if (current_tags.indexOf(tag.textContent.replace(/ /g, "_")) > -1) { + $(tag).addClass("selected"); + } + }); +} + +RelatedTag.tags_include = function(name) { + var current = $("#upload_tag_string,#post_tag_string").val().toLowerCase().match(/\S+/g) || []; + return $.inArray(name.toLowerCase(), current) > -1; +} + +RelatedTag.toggle_tag = function(e) { + var $field = $("#upload_tag_string,#post_tag_string"); + var tag = $(e.target).html().replace(/ /g, "_").replace(/>/g, ">").replace(/</g, "<").replace(/&/g, "&"); + + if (RelatedTag.tags_include(tag)) { + var escaped_tag = Utility.regexp_escape(tag); + $field.val($field.val().replace(new RegExp("(^|\\s)" + escaped_tag + "($|\\s)", "gi"), "$1$2")); + } else { + $field.val($field.val() + " " + tag); + } + $field.val($field.val().trim().replace(/ +/g, " ") + " "); + + RelatedTag.update_selected(); + + // The timeout is needed on Chrome since it will clobber the field attribute otherwise + setTimeout(function () { $field.prop('selectionStart', $field.val().length);}, 100); + e.preventDefault(); +} + +RelatedTag.show = function(e) { + $(document).trigger("danbooru:show-related-tags"); + $("#related-tags-container").removeClass("hidden").addClass("visible"); + + if (e) { + e.preventDefault(); + } +} + +RelatedTag.hide = function(e) { + $("#related-tags-container").removeClass("visible").addClass("hidden"); + + if (e) { + e.preventDefault(); + } +} + +$(function() { + RelatedTag.initialize_all(); +}); + +export default RelatedTag + diff --git a/app/javascript/src/javascripts/related_tag.js.erb b/app/javascript/src/javascripts/related_tag.js.erb deleted file mode 100644 index 85980c60e..000000000 --- a/app/javascript/src/javascripts/related_tag.js.erb +++ /dev/null @@ -1,331 +0,0 @@ -import Upload from './uploads'; -import Utility from './utility'; -import Cookie from './cookie'; - -let RelatedTag = {}; - -RelatedTag.initialize_all = function() { - if ($("#c-posts #a-show").length || $("#c-uploads #a-new").length) { - this.initialize_buttons(); - $("#upload_tag_string,#post_tag_string").on("keyup.danbooru.relatedTags", RelatedTag.update_selected); - $("#related-tags-container").on("click.danbooru", "#artist-related-tags-column a.del", RelatedTag.disable_artist_url) - } -} - -RelatedTag.initialize_buttons = function() { - this.common_bind("#related-tags-button", ""); - <% TagCategory.related_button_list.each do |category| %> - RelatedTag.common_bind("#related-<%= category %>-button", "<%= category %>"); // eslint-disable-line indent - <% end %> -} - -RelatedTag.tags_include = function(name) { - var current = $("#upload_tag_string,#post_tag_string").val().toLowerCase().match(/\S+/g) || []; - return $.inArray(name.toLowerCase(), current) > -1; -} - -RelatedTag.common_bind = function(button_name, category) { - $(button_name).on("click.danbooru", function(e) { - var $dest = $("#related-tags"); - $dest.empty(); - RelatedTag.build_recent_and_frequent($dest); - $dest.append("Loading..."); - $.get("/related_tag.json", { - "query": RelatedTag.current_tag(), - "category": category - }, RelatedTag.process_response); - e.preventDefault(); - }); -} - -RelatedTag.current_tag = function() { - // 1. abc def | -> def - // 2. abc def| -> def - // 3. abc de|f -> def - // 4. abc |def -> def - // 5. abc| def -> abc - // 6. ab|c def -> abc - // 7. |abc def -> abc - // 8. | abc def -> abc - - var $field = $("#upload_tag_string,#post_tag_string"); - var string = $field.val(); - var n = string.length; - var a = $field.prop('selectionStart'); - var b = $field.prop('selectionStart'); - - if ((a > 0) && (a < (n - 1)) && (!/\s/.test(string[a])) && (/\s/.test(string[a - 1]))) { - // 4 is the only case where we need to scan forward. in all other cases we - // can drag a backwards, and then drag b forwards. - - while ((b < n) && (!/\s/.test(string[b]))) { - b++; - } - } else if (string.search(/\S/) > b) { // case 8 - b = string.search(/\S/); - while ((b < n) && (!/\s/.test(string[b]))) { - b++; - } - } else { - while ((a > 0) && ((/\s/.test(string[a])) || (string[a] === undefined))) { - a--; - b--; - } - - while ((a > 0) && (!/\s/.test(string[a - 1]))) { - a--; - b--; - } - - while ((b < (n - 1)) && (!/\s/.test(string[b]))) { - b++; - } - } - - b++; - return string.slice(a, b); -} - -RelatedTag.process_response = function(data) { - RelatedTag.recent_search = data; - RelatedTag.build_all(); -} - -RelatedTag.update_selected = function(e) { - var current_tags = $("#upload_tag_string,#post_tag_string").val().toLowerCase().match(/\S+/g) || []; - var $all_tags = $("#related-tags a"); - $all_tags.removeClass("selected"); - - $all_tags.each(function(i, tag) { - if (current_tags.indexOf(tag.textContent.replace(/ /g, "_")) > -1) { - $(tag).addClass("selected"); - } - }); -} - -RelatedTag.build_all = function() { - if (RelatedTag.recent_search === null || RelatedTag.recent_search === undefined) { - return; - } - - RelatedTag.show(); - - var query = RelatedTag.recent_search.query; - var related_tags = RelatedTag.recent_search.tags; - var wiki_page_tags = RelatedTag.recent_search.wiki_page_tags; - var other_wikis = RelatedTag.recent_search.other_wikis; - var $dest = $("#related-tags"); - $dest.empty(); - - this.build_recent_and_frequent($dest); - - $dest.append(this.build_html(query, related_tags, "general")); - this.build_translated($dest); - if (wiki_page_tags.length) { - $dest.append(RelatedTag.build_html("wiki:" + query, wiki_page_tags, "wiki")); - } - $.each(other_wikis, function(i, wiki) { - $dest.append(RelatedTag.build_html("wiki:" + wiki.title, wiki.wiki_page_tags, "otherwiki" + i.toString())); - }); - if (RelatedTag.recent_artists) { - var tags = []; - if (RelatedTag.recent_artists.length === 0) { - tags.push([" none", 0]); - } else if (RelatedTag.recent_artists.length === 1) { - tags.push([RelatedTag.recent_artists[0].name, 1]); - if (RelatedTag.recent_artists[0].is_banned === true) { - tags.push(["BANNED_ARTIST", "banned"]); - } - $.each(RelatedTag.recent_artists[0].sorted_urls, function(i, url) { - var x = url.url; - if (!url.is_active) { - x = "-" + x; - } - tags.push([" " + x, 0]); - }); - } else if (RelatedTag.recent_artists.length >= 10) { - tags.push([" none", 0]); - } else { - $.each(RelatedTag.recent_artists, function(i, artist) { - tags.push([artist.name, 1]); - }); - } - $dest.append(RelatedTag.build_html("artist", tags, "artist", true)); - } -} - -RelatedTag.build_recent_and_frequent = function($dest) { - var recent_tags = Cookie.get("recent_tags_with_categories"); - var favorite_tags = Cookie.get("favorite_tags_with_categories"); - if (recent_tags.length) { - $dest.append(this.build_html("recent", this.other_tags(recent_tags), "recent")); - } - if (favorite_tags.length) { - $dest.append(this.build_html("frequent", this.other_tags(favorite_tags), "frequent")); - } -} - -RelatedTag.other_tags = function(string) { - if (string && string.length) { - return $.map(string.match(/\S+ \d+/g), function(x, i) { - var submatch = x.match(/(\S+) (\d+)/); - return [[submatch[1], submatch[2]]]; - }); - } else { - return []; - } -} - -RelatedTag.build_translated = function($dest) { - if (RelatedTag.translated_tags && RelatedTag.translated_tags.length) { - $dest.append(this.build_html("Translated Tags", RelatedTag.translated_tags, "translated")); - } -} - -RelatedTag.build_html = function(query, related_tags, name, is_wide_column) { - if (query === null || query === "") { - return ""; - } - - query = query.replace(/_/g, " "); - var header = $(""); - - var match = query.match(/^wiki:(.+)/); - if (match) { - header.html($("").attr("href", "/wiki_pages?title=" + encodeURIComponent(match[1])).attr("target", "_blank").text(query)); - } else { - header.text(query); - } - - var $div = $(""); - $div.attr("id", name + "-related-tags-column"); - $div.addClass("tag-column"); - if (is_wide_column) { - $div.addClass("wide-column"); - } - var $ul = $("