From 1fa2f3821497d5529a6753cee84cf5ca679e8bcc Mon Sep 17 00:00:00 2001 From: erdgeist Date: Sun, 5 Jul 2026 21:49:21 +0200 Subject: Fix admin search results colliding with other search widgets layouts/admin.html.erb's top-bar search results div shared id "search_results" with nodes#new/nodes#edit's parent-search widget - since the layout renders on every admin page, whichever widget's JS ran last silently won the shared ID, putting top-bar results into the parent-search box on affected pages. Renamed to "menu_search_results" and updated admin_search.js to match. Also modernizes admin_search.js's event bindings from keyup/keydown/ keypress/paste/cut + .attr("value") to input + .val() throughout (menu_items, parent_search, move_to_search) - the multi-event binding was working around old IE compatibility that .val() + "input" already handles correctly. parent_search's result rendering now matches menu_search's convention (real

/ markup with a .result_path span) instead of a bare in a throwaway wrapper div, so the same CSS rule now correctly applies to both. menu_search's JSON response gains node_path per result, matching what admin_search's own results already provide - not yet consumed by parent_search/move_to_search, which still render click-to-select links rather than navigable ones (correct for their purpose - selecting a value, not leaving the page). Known remaining gap, not fixed here: menu_items, parent_search, and move_to_search still all target the literal id "search_results" between themselves. No live collision today since none of the three currently share a page, but it's the same fragility as the bug above - tracked alongside the existing menu_items/parent_search/move_to_search consolidation backlog item rather than treated as resolved. --- app/controllers/admin_controller.rb | 33 ++++++------ app/views/layouts/admin.html.erb | 2 +- public/javascripts/admin_search.js | 105 +++++++++++++++++++++--------------- 3 files changed, 81 insertions(+), 59 deletions(-) diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb index d671384..e0098b0 100644 --- a/app/controllers/admin_controller.rb +++ b/app/controllers/admin_controller.rb @@ -29,46 +29,49 @@ class AdminController < ApplicationController .order("updated_at desc") .uniq.first(50) end - + + def conventions + @node_kinds = CccConventions::NODE_KINDS + end + def search @results = Node.search params[:search_term], :per_page => 1000 - + respond_to do |format| format.html do render :template => 'admin/search_results' end - format.js do - render( :json => @results.map do |node| + format.js do + render( :json => @results.map do |node| if node { :id => node.id, :title => node.title, :unique_name => node.unique_name, :node_path => node_path(node) } end end ) - - end + + end end end - + def menu_search if params[:search_term] == "Root" @results = [Node.root] else @results = Node.search params[:search_term] end - + respond_to do |format| format.html do render :partial => 'admin/menu_search_results' end - - format.js do - render( :json => @results.map do |node| - {:node_id => node.id, :title => node.title, :unique_name => node.unique_name} + + format.js do + render( :json => @results.map do |node| + {:node_id => node.id, :title => node.title, :unique_name => node.unique_name, :node_path => node_path(node)} end ) - - end + + end end end - end diff --git a/app/views/layouts/admin.html.erb b/app/views/layouts/admin.html.erb index 4536693..a7ce68a 100644 --- a/app/views/layouts/admin.html.erb +++ b/app/views/layouts/admin.html.erb @@ -49,7 +49,7 @@ Search: <%= text_field_tag :search_term, nil, autocomplete: "off" %> <% end %> -

diff --git a/public/javascripts/admin_search.js b/public/javascripts/admin_search.js index 9bf878b..2565929 100644 --- a/public/javascripts/admin_search.js +++ b/public/javascripts/admin_search.js @@ -36,8 +36,8 @@ admin_search = { } }); } else { - $('#search_results').slideUp(); - $('#search_results').empty(); + $('#menu_search_results').slideUp(); + $('#menu_search_results').empty(); } }); }, @@ -52,33 +52,33 @@ admin_search = { }, show_results : function(results) { - $('#search_results').empty(); + $('#menu_search_results').empty(); if (results.length) { - $('#search_results').append( + $('#menu_search_results').append( "

Press Enter to see all results ⏎

" ); } for (result in results) { - $('#search_results').append( + $('#menu_search_results').append( "

" + results[result].title + "" + results[result].unique_name + "" + "

" ); } - $('#search_results').slideDown(); + $('#menu_search_results').slideDown(); } }; menu_items = { initialize_search : function() { - $("#menu_search_term").bind("keyup", function() { - if ($(this).attr("value")) { + $("#menu_search_term").bind("input", function() { + if ($(this).val()) { $.ajax({ type: "GET", url: ADMIN_MENU_SEARCH_URL, - data: "search_term=" + $(this).attr("value"), + data: "search_term=" + $(this).val(), dataType: "json", success : function(results) { menu_items.show_results(results); @@ -125,12 +125,12 @@ parent_search = { initialize_search : function() { parent_search.initialize_radio_buttons(); - $("#parent_search_term").bind("keyup", function() { - if ($(this).attr("value")) { + $("#parent_search_term").bind("input", function() { + if ($(this).val()) { $.ajax({ type: "GET", url: ADMIN_MENU_SEARCH_URL, - data: "search_term=" + $(this).attr("value"), + data: "search_term=" + $(this).val(), dataType: "json", success : function(results) { parent_search.show_results(results); @@ -142,22 +142,31 @@ parent_search = { $('#search_results').empty(); } }); + + $("#title").bind("input", function() { + parent_search.update_resulting_path(); + }); + + $("#copy_resulting_path").bind("click", function() { + var path = $("#resulting_path").text(); + if (path === "—" || !navigator.clipboard) return; + navigator.clipboard.writeText(path); + }); }, show_results : function(results) { $("#search_results").empty(); var found = false; for (result in results) { - var link = $((""+ results[result].title + "")); - $(link).bind("click", parent_search.link_closure(results[result])); + var link = $(( + "

" + results[result].title + + "" + results[result].unique_name + "" + + "

")); - // Sometimes I don't get jquery; wrap() didn't work *sigh* - // Guess I'll need a book someday or another framework - var wrapper = $("
"); - $(wrapper).append(link); + $(link).bind("click", parent_search.link_closure(results[result])); - $("#search_results").append(wrapper); + $("#search_results").append(link); found = true; } if (found) @@ -166,51 +175,61 @@ parent_search = { link_closure : function(node) { var barf = function(){ - $("#parent_search_term").attr("value", node.title); - $("#parent_id").attr("value", node.node_id); + $("#parent_search_term").val(node.title); + $("#parent_id").val(node.node_id).attr("data-unique-name", node.unique_name); $('#search_results').slideUp(); $('#search_results').empty(); + parent_search.update_resulting_path(); return false; } return barf; }, - initialize_radio_buttons : function() { - $("#kind_top_level").bind("change", function(){ - $("#parent_search_field").hide(); - }); + update_resulting_path : function() { + var kind = $("input[name='kind']:checked"); + var title = $("#title").val(); - $("#kind_update").bind("change", function(){ - $("#parent_search_field").hide(); - }); + if (title === "") { + $("#resulting_path").text("—"); + return; + } - $("#kind_press_release").bind("change", function(){ - $("#parent_search_field").hide(); - }); + var prefix = kind.val() === "generic" + ? ($("#parent_id").attr("data-unique-name") || "") + : (kind.attr("data-path-prefix") || ""); - $("#kind_generic").bind("change", function(){ - $("#parent_search_field").show(); - }); + clearTimeout(parent_search.path_timeout); + parent_search.path_timeout = setTimeout(function() { + $.get("/nodes/parameterize_preview", { title: title }, function(slug) { + $("#resulting_path").text(window.location.origin + "/" + (prefix ? prefix + "/" : "") + slug); + }); + }, 300); + }, + initialize_radio_buttons : function() { + $("input[name='kind']").bind("change", function(){ + if ($(this).val() === "generic") { + $("#parent_search_field").show(); + } else { + $("#parent_search_field").hide(); + } + parent_search.update_resulting_path(); + }); } } move_to_search = { initialize_search : function() { - $("#move_to_search_term").bind("keyup", function() { move_to_search.do_search($(this))}); - $("#move_to_search_term").bind("keydown", function() { move_to_search.do_search($(this))}); - $("#move_to_search_term").bind("keypress", function() { move_to_search.do_search($(this))}); - $("#move_to_search_term").bind("paste", function() { move_to_search.do_search($(this))}); - $("#move_to_search_term").bind("cut", function() { move_to_search.do_search($(this))}); + $("#move_to_search_term").bind("input", function() {move_to_search.do_search($(this))}); }, do_search : function(_this) { - if (_this.attr("value")) { + if (_this.val()) { $.ajax({ type: "GET", url: ADMIN_MENU_SEARCH_URL, - data: "search_term=" + _this.attr("value"), + data: "search_term=" + _this.val(), dataType: "json", success : function(results) { move_to_search.show_results(results); @@ -248,8 +267,8 @@ move_to_search = { link_closure : function(node) { var barf = function(){ - $("#move_to_search_term").attr("value", node.title); - $("#node_staged_parent_id").attr("value", node.node_id); + $("#move_to_search_term").val(node.title); + $("#node_staged_parent_id").val(node.node_id); $('#search_results').slideUp(); $('#search_results').empty(); return false; -- cgit v1.3