diff options
| author | erdgeist <erdgeist@erdgeist.org> | 2026-07-13 23:33:11 +0200 |
|---|---|---|
| committer | erdgeist <erdgeist@erdgeist.org> | 2026-07-13 23:33:11 +0200 |
| commit | 8eab68f2c5a3c126e2fec2ecdfa7ace87ce0937b (patch) | |
| tree | f446ebc26a7707c7b64a937aa51a155df146c80a /public/javascripts/admin_search.js | |
| parent | 42714c697273a7117c6b355fab26c8c35e336ad1 (diff) | |
| parent | cdf5d9941ca866d437612d2f863eac6eb0b3db12 (diff) | |
Merge branch 'erdgeist-revive-events'
Diffstat (limited to 'public/javascripts/admin_search.js')
| -rw-r--r-- | public/javascripts/admin_search.js | 393 |
1 files changed, 208 insertions, 185 deletions
diff --git a/public/javascripts/admin_search.js b/public/javascripts/admin_search.js index 9bf878b..7604bb7 100644 --- a/public/javascripts/admin_search.js +++ b/public/javascripts/admin_search.js | |||
| @@ -1,5 +1,4 @@ | |||
| 1 | admin_search = { | 1 | admin_search = { |
| 2 | |||
| 3 | initialize : function() { | 2 | initialize : function() { |
| 4 | $(document).bind("keydown", 'Alt+f', function(){ | 3 | $(document).bind("keydown", 'Alt+f', function(){ |
| 5 | admin_search.display_toggle(); | 4 | admin_search.display_toggle(); |
| @@ -20,25 +19,12 @@ admin_search = { | |||
| 20 | } | 19 | } |
| 21 | }); | 20 | }); |
| 22 | 21 | ||
| 23 | $("#search_term").bind("input", function() { | 22 | initSearchPicker({ |
| 24 | if (!$('#search_widget').is(':visible')) return; | 23 | inputSelector: "#search_term", |
| 25 | if ($(this).val()) { | 24 | resultsSelector: "#menu_search_results", |
| 26 | $.ajax({ | 25 | url: ADMIN_SEARCH_URL, |
| 27 | type: "GET", | 26 | isActive: function() { return $('#search_widget').is(':visible'); }, |
| 28 | url: ADMIN_SEARCH_URL, | 27 | resultsHeaderHtml: "<p class='search_more'>Press Enter to see all results ⏎</p>" |
| 29 | data: "search_term=" + $(this).val(), | ||
| 30 | dataType: "json", | ||
| 31 | success: function(results) { | ||
| 32 | admin_search.show_results(results); | ||
| 33 | }, | ||
| 34 | error: function(xhr, status, error) { | ||
| 35 | console.log("Ajax error:", status, error, xhr.status, xhr.responseText); | ||
| 36 | } | ||
| 37 | }); | ||
| 38 | } else { | ||
| 39 | $('#search_results').slideUp(); | ||
| 40 | $('#search_results').empty(); | ||
| 41 | } | ||
| 42 | }); | 28 | }); |
| 43 | }, | 29 | }, |
| 44 | 30 | ||
| @@ -49,75 +35,155 @@ admin_search = { | |||
| 49 | $('#search_widget').fadeIn(); | 35 | $('#search_widget').fadeIn(); |
| 50 | $('#search_term').focus(); | 36 | $('#search_term').focus(); |
| 51 | } | 37 | } |
| 52 | }, | ||
| 53 | |||
| 54 | show_results : function(results) { | ||
| 55 | $('#search_results').empty(); | ||
| 56 | if (results.length) { | ||
| 57 | $('#search_results').append( | ||
| 58 | "<p class='search_more'>Press Enter to see all results ⏎</p>" | ||
| 59 | ); | ||
| 60 | } | ||
| 61 | for (result in results) { | ||
| 62 | $('#search_results').append( | ||
| 63 | "<p><a href='" + results[result].node_path + "'>" + | ||
| 64 | results[result].title + | ||
| 65 | "<span class='result_path'>" + results[result].unique_name + "</span>" + | ||
| 66 | "</a></p>" | ||
| 67 | ); | ||
| 68 | } | ||
| 69 | $('#search_results').slideDown(); | ||
| 70 | } | 38 | } |
| 71 | }; | 39 | }; |
| 72 | 40 | ||
| 73 | menu_items = { | 41 | function initSearchPicker(options) { |
| 42 | var inputSelector = options.inputSelector; | ||
| 43 | var resultsSelector = options.resultsSelector; | ||
| 44 | var url = options.url || ADMIN_MENU_SEARCH_URL; | ||
| 45 | var onSelect = options.onSelect; | ||
| 46 | var isActive = options.isActive; | ||
| 47 | var resultsHeaderHtml = options.resultsHeaderHtml; | ||
| 48 | var renderResults = options.renderResults; | ||
| 49 | var loadOnFocus = options.loadOnFocus; // optional, fires an initial search on focus with no term typed yet | ||
| 50 | var requestId = 0; | ||
| 51 | var timeout; | ||
| 52 | var results = $(resultsSelector); | ||
| 74 | 53 | ||
| 75 | initialize_search : function() { | 54 | function runSearch(term) { |
| 76 | $("#menu_search_term").bind("keyup", function() { | 55 | var thisRequest = ++requestId; |
| 77 | if ($(this).attr("value")) { | 56 | $.ajax({ |
| 78 | $.ajax({ | 57 | type: "GET", |
| 79 | type: "GET", | 58 | url: url, |
| 80 | url: ADMIN_MENU_SEARCH_URL, | 59 | data: "search_term=" + term, |
| 81 | data: "search_term=" + $(this).attr("value"), | 60 | dataType: "json", |
| 82 | dataType: "json", | 61 | success: function(data) { |
| 83 | success : function(results) { | 62 | if (thisRequest !== requestId) return; |
| 84 | menu_items.show_results(results); | 63 | results.empty(); |
| 64 | |||
| 65 | var found; | ||
| 66 | if (renderResults) { | ||
| 67 | found = renderResults(data, results, resultsHeaderHtml); | ||
| 68 | } else { | ||
| 69 | if (data.length && resultsHeaderHtml) { | ||
| 70 | results.append(resultsHeaderHtml); | ||
| 85 | } | 71 | } |
| 86 | }); | 72 | found = false; |
| 87 | } | 73 | for (var i = 0; i < data.length; i++) { |
| 88 | else { | 74 | (function(node) { |
| 89 | $('#search_results').slideUp(); | 75 | var link; |
| 90 | $('#search_results').empty(); | 76 | if (onSelect) { |
| 77 | link = $( | ||
| 78 | "<p><a href='#'>" + node.title + | ||
| 79 | "<span class='result_path'>" + node.unique_name + "</span></a></p>" | ||
| 80 | ); | ||
| 81 | link.find("a").bind("click", function() { | ||
| 82 | onSelect(node); | ||
| 83 | results.slideUp(); | ||
| 84 | results.empty(); | ||
| 85 | return false; | ||
| 86 | }); | ||
| 87 | } else { | ||
| 88 | link = $( | ||
| 89 | "<p><a href='" + node.node_path + "'>" + node.title + | ||
| 90 | "<span class='result_path'>" + node.unique_name + "</span></a></p>" | ||
| 91 | ); | ||
| 92 | } | ||
| 93 | results.append(link); | ||
| 94 | found = true; | ||
| 95 | })(data[i]); | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | if (found) { | ||
| 100 | results.slideDown(); | ||
| 101 | } else { | ||
| 102 | results.slideUp(); | ||
| 103 | } | ||
| 104 | }, | ||
| 105 | error: function(xhr, status, error) { | ||
| 106 | console.log("Ajax error:", status, error, xhr.status, xhr.responseText); | ||
| 91 | } | 107 | } |
| 92 | }); | 108 | }); |
| 93 | }, | 109 | } |
| 94 | 110 | ||
| 95 | show_results : function(results) { | 111 | $(inputSelector).bind("input", function() { |
| 96 | $("#search_results").empty(); | 112 | if (isActive && !isActive()) return; |
| 97 | for (result in results) { | ||
| 98 | var link = $(("<a href='#'>"+ results[result].title + "</a>")); | ||
| 99 | $(link).bind("click", menu_items.link_closure(results[result])); | ||
| 100 | 113 | ||
| 114 | var term = $(this).val(); | ||
| 115 | clearTimeout(timeout); | ||
| 101 | 116 | ||
| 102 | // Sometimes I don't get jquery; wrap() didn't work *sigh* | 117 | if (!term) { |
| 103 | // Guess I'll need a book someday or another framework | 118 | results.slideUp(); |
| 104 | var wrapper = $("<div></div>"); | 119 | results.empty(); |
| 105 | $(wrapper).append(link) | 120 | return; |
| 121 | } | ||
| 106 | 122 | ||
| 107 | $("#search_results").append(wrapper); | 123 | timeout = setTimeout(function() { runSearch(term); }, 250); |
| 124 | }); | ||
| 108 | 125 | ||
| 109 | } | 126 | if (loadOnFocus) { |
| 110 | }, | 127 | $(inputSelector).bind("focus", function() { |
| 128 | if (isActive && !isActive()) return; | ||
| 129 | if ($(this).val()) return; // the input handler above already covers a real term | ||
| 130 | runSearch(""); | ||
| 131 | }); | ||
| 132 | } | ||
| 133 | } | ||
| 111 | 134 | ||
| 112 | link_closure : function(node) { | 135 | dashboard_search = { |
| 113 | var barf = function(){ | 136 | initialize : function() { |
| 114 | $("#menu_item_node_id").val(node.node_id); | 137 | initSearchPicker({ |
| 115 | $("#menu_item_path").val("/" + node.unique_name); | 138 | inputSelector: "#dashboard_search_term", |
| 116 | $("#menu_item_title").val(node.title); | 139 | resultsSelector: "#dashboard_search_results", |
| 117 | return false; | 140 | url: DASHBOARD_SEARCH_URL, |
| 118 | } | 141 | resultsHeaderHtml: "<p class='search_more'>Press Enter to see all results ⏎</p>", |
| 142 | renderResults: function(data, results, resultsHeaderHtml) { | ||
| 143 | var found = false; | ||
| 144 | |||
| 145 | if ((data.tags.length || data.nodes.length) && resultsHeaderHtml) { | ||
| 146 | results.append(resultsHeaderHtml); | ||
| 147 | } | ||
| 148 | |||
| 149 | if (data.tags.length) { | ||
| 150 | results.append("<p class='search_group_label'>Tags</p>"); | ||
| 151 | var tag_row = $("<div class='search_tag_row'></div>"); | ||
| 152 | data.tags.forEach(function(tag) { | ||
| 153 | tag_row.append("<a class='search_tag_pill' href='" + tag.tag_path + "'>" + tag.name + "</a>"); | ||
| 154 | found = true; | ||
| 155 | }); | ||
| 156 | results.append(tag_row); | ||
| 157 | } | ||
| 158 | |||
| 159 | if (data.nodes.length) { | ||
| 160 | results.append("<p class='search_group_label'>Pages</p>"); | ||
| 161 | data.nodes.forEach(function(node) { | ||
| 162 | results.append( | ||
| 163 | "<p><a href='" + node.node_path + "'>" + node.title + | ||
| 164 | "<span class='result_path'>" + node.unique_name + "</span></a></p>" | ||
| 165 | ); | ||
| 166 | found = true; | ||
| 167 | }); | ||
| 168 | } | ||
| 169 | |||
| 170 | return found; | ||
| 171 | } | ||
| 172 | }); | ||
| 173 | } | ||
| 174 | }; | ||
| 119 | 175 | ||
| 120 | return barf; | 176 | menu_items = { |
| 177 | initialize_search : function() { | ||
| 178 | initSearchPicker({ | ||
| 179 | inputSelector: "#menu_search_term", | ||
| 180 | resultsSelector: "#menu_item_search_results", | ||
| 181 | onSelect: function(node) { | ||
| 182 | $("#menu_item_node_id").val(node.node_id); | ||
| 183 | $("#menu_item_path").val("/" + node.unique_name); | ||
| 184 | $("#menu_item_title").val(node.title); | ||
| 185 | } | ||
| 186 | }); | ||
| 121 | } | 187 | } |
| 122 | }; | 188 | }; |
| 123 | 189 | ||
| @@ -125,136 +191,93 @@ parent_search = { | |||
| 125 | initialize_search : function() { | 191 | initialize_search : function() { |
| 126 | parent_search.initialize_radio_buttons(); | 192 | parent_search.initialize_radio_buttons(); |
| 127 | 193 | ||
| 128 | $("#parent_search_term").bind("keyup", function() { | 194 | initSearchPicker({ |
| 129 | if ($(this).attr("value")) { | 195 | inputSelector: "#parent_search_term", |
| 130 | $.ajax({ | 196 | resultsSelector: "#parent_search_results", |
| 131 | type: "GET", | 197 | onSelect: function(node) { |
| 132 | url: ADMIN_MENU_SEARCH_URL, | 198 | $("#parent_search_term").val(node.title); |
| 133 | data: "search_term=" + $(this).attr("value"), | 199 | $("#parent_id").val(node.node_id).attr("data-unique-name", node.unique_name); |
| 134 | dataType: "json", | 200 | parent_search.update_resulting_path(); |
| 135 | success : function(results) { | ||
| 136 | parent_search.show_results(results); | ||
| 137 | } | ||
| 138 | }); | ||
| 139 | } | ||
| 140 | else { | ||
| 141 | $('#search_results').slideUp(); | ||
| 142 | $('#search_results').empty(); | ||
| 143 | } | 201 | } |
| 144 | }); | 202 | }); |
| 145 | }, | ||
| 146 | 203 | ||
| 147 | show_results : function(results) { | 204 | $("#title").bind("input", function() { |
| 148 | $("#search_results").empty(); | 205 | parent_search.update_resulting_path(); |
| 149 | var found = false; | 206 | }); |
| 150 | for (result in results) { | ||
| 151 | var link = $(("<a href='#'>"+ results[result].title + "</a>")); | ||
| 152 | $(link).bind("click", parent_search.link_closure(results[result])); | ||
| 153 | 207 | ||
| 208 | $("#copy_resulting_path").bind("click", function() { | ||
| 209 | var path = $("#resulting_path").text(); | ||
| 210 | if (path === "—" || !navigator.clipboard) return; | ||
| 211 | navigator.clipboard.writeText(path); | ||
| 212 | }); | ||
| 213 | }, | ||
| 154 | 214 | ||
| 155 | // Sometimes I don't get jquery; wrap() didn't work *sigh* | 215 | update_resulting_path : function() { |
| 156 | // Guess I'll need a book someday or another framework | 216 | var kind = $("input[name='kind']:checked"); |
| 157 | var wrapper = $("<div></div>"); | 217 | var title = $("#title").val(); |
| 158 | $(wrapper).append(link); | ||
| 159 | 218 | ||
| 160 | $("#search_results").append(wrapper); | 219 | if (title === "") { |
| 161 | found = true; | 220 | $("#resulting_path").text("—"); |
| 221 | return; | ||
| 162 | } | 222 | } |
| 163 | if (found) | ||
| 164 | $('#search_results').slideDown(); | ||
| 165 | }, | ||
| 166 | 223 | ||
| 167 | link_closure : function(node) { | 224 | var prefix = kind.val() === "generic" |
| 168 | var barf = function(){ | 225 | ? ($("#parent_id").attr("data-unique-name") || "") |
| 169 | $("#parent_search_term").attr("value", node.title); | 226 | : (kind.attr("data-path-prefix") || ""); |
| 170 | $("#parent_id").attr("value", node.node_id); | ||
| 171 | $('#search_results').slideUp(); | ||
| 172 | $('#search_results').empty(); | ||
| 173 | return false; | ||
| 174 | } | ||
| 175 | 227 | ||
| 176 | return barf; | 228 | clearTimeout(parent_search.path_timeout); |
| 229 | parent_search.path_timeout = setTimeout(function() { | ||
| 230 | $.get(PARAMETERIZE_PREVIEW_URL, { title: title }, function(slug) { | ||
| 231 | $("#resulting_path").text(window.location.origin + "/" + (prefix ? prefix + "/" : "") + slug); | ||
| 232 | }); | ||
| 233 | }, 300); | ||
| 177 | }, | 234 | }, |
| 178 | 235 | ||
| 179 | initialize_radio_buttons : function() { | 236 | initialize_radio_buttons : function() { |
| 180 | $("#kind_top_level").bind("change", function(){ | 237 | parent_search.sync_parent_field(); |
| 181 | $("#parent_search_field").hide(); | 238 | $("input[name='kind']").bind("change", function() { |
| 182 | }); | 239 | parent_search.sync_parent_field(); |
| 183 | 240 | parent_search.update_resulting_path(); | |
| 184 | $("#kind_update").bind("change", function(){ | ||
| 185 | $("#parent_search_field").hide(); | ||
| 186 | }); | 241 | }); |
| 242 | }, | ||
| 187 | 243 | ||
| 188 | $("#kind_press_release").bind("change", function(){ | 244 | sync_parent_field : function() { |
| 245 | var kind = $("input[name='kind']:checked").val(); | ||
| 246 | if (kind === "generic") { | ||
| 247 | $("#parent_search_field").show(); | ||
| 248 | } else { | ||
| 189 | $("#parent_search_field").hide(); | 249 | $("#parent_search_field").hide(); |
| 190 | }); | 250 | } |
| 251 | } | ||
| 252 | }; | ||
| 191 | 253 | ||
| 192 | $("#kind_generic").bind("change", function(){ | 254 | move_to_search = { |
| 193 | $("#parent_search_field").show(); | 255 | initialize_search : function() { |
| 256 | initSearchPicker({ | ||
| 257 | inputSelector: "#move_to_search_term", | ||
| 258 | resultsSelector: "#move_to_search_results", | ||
| 259 | onSelect: function(node) { | ||
| 260 | $("#move_to_search_term").val(node.title); | ||
| 261 | $("#node_staged_parent_id").val(node.node_id); | ||
| 262 | } | ||
| 194 | }); | 263 | }); |
| 195 | |||
| 196 | } | 264 | } |
| 197 | } | 265 | }; |
| 198 | 266 | ||
| 199 | move_to_search = { | 267 | event_search = { |
| 200 | initialize_search : function() { | 268 | initialize_search : function() { |
| 201 | $("#move_to_search_term").bind("keyup", function() { move_to_search.do_search($(this))}); | 269 | initSearchPicker({ |
| 202 | $("#move_to_search_term").bind("keydown", function() { move_to_search.do_search($(this))}); | 270 | inputSelector: "#event_node_search_term", |
| 203 | $("#move_to_search_term").bind("keypress", function() { move_to_search.do_search($(this))}); | 271 | resultsSelector: "#event_search_results", |
| 204 | $("#move_to_search_term").bind("paste", function() { move_to_search.do_search($(this))}); | 272 | onSelect: function(node) { |
| 205 | $("#move_to_search_term").bind("cut", function() { move_to_search.do_search($(this))}); | 273 | $("#event_node_search_term").val(node.title); |
| 206 | }, | 274 | $("#event_node_id").val(node.node_id); |
| 207 | 275 | ||
| 208 | do_search : function(_this) { | 276 | var title_field = $("#event_title"); |
| 209 | if (_this.attr("value")) { | 277 | if (title_field.val() === "") { |
| 210 | $.ajax({ | 278 | $("#event_title_hint").text("Using \"" + node.title + "\" from the associated node."); |
| 211 | type: "GET", | ||
| 212 | url: ADMIN_MENU_SEARCH_URL, | ||
| 213 | data: "search_term=" + _this.attr("value"), | ||
| 214 | dataType: "json", | ||
| 215 | success : function(results) { | ||
| 216 | move_to_search.show_results(results); | ||
| 217 | } | 279 | } |
| 218 | }); | 280 | } |
| 219 | } | 281 | }); |
| 220 | else { | ||
| 221 | $('#search_results').slideUp(); | ||
| 222 | $('#search_results').empty(); | ||
| 223 | } | ||
| 224 | }, | ||
| 225 | |||
| 226 | show_results : function(results) { | ||
| 227 | $("#search_results").empty(); | ||
| 228 | var found = false; | ||
| 229 | for (result in results) { | ||
| 230 | var link = $(("<a href='#'>"+ results[result].title + "</a>")); | ||
| 231 | $(link).bind("click", move_to_search.link_closure(results[result])); | ||
| 232 | |||
| 233 | |||
| 234 | // Sometimes I don't get jquery; wrap() didn't work *sigh* | ||
| 235 | // Guess I'll need a book someday or another framework | ||
| 236 | var wrapper = $("<div></div>"); | ||
| 237 | $(wrapper).append(link) | ||
| 238 | |||
| 239 | $("#search_results").append(wrapper); | ||
| 240 | found = true; | ||
| 241 | } | ||
| 242 | if (found) | ||
| 243 | $('#search_results').slideDown(); | ||
| 244 | else | ||
| 245 | $('#search_results').slideUp(); | ||
| 246 | |||
| 247 | }, | ||
| 248 | |||
| 249 | link_closure : function(node) { | ||
| 250 | var barf = function(){ | ||
| 251 | $("#move_to_search_term").attr("value", node.title); | ||
| 252 | $("#node_staged_parent_id").attr("value", node.node_id); | ||
| 253 | $('#search_results').slideUp(); | ||
| 254 | $('#search_results').empty(); | ||
| 255 | return false; | ||
| 256 | } | ||
| 257 | |||
| 258 | return barf; | ||
| 259 | } | 282 | } |
| 260 | } | 283 | }; |
