Skip to content

Commit a27f0e3

Browse files
committed
Use content spinner for tab changes
Why are these changes being introduced: * Initial implementation used full page refresh but that removed the desired spinners Relevant ticket(s): * https://mitlibraries.atlassian.net/browse/USE-135 How does this address that need: * Moves back to target content refresh with turbo frame * Adds JavaScript to update hidden form element and set active class on tab * Introduces Feature to slow down fast requests when testing page elements that are fleeting like spinners/loaders
1 parent ed6ef11 commit a27f0e3

File tree

5 files changed

+76
-5
lines changed

5 files changed

+76
-5
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ See `Optional Environment Variables` for more information.
9797
- `FEATURE_GEODATA`: Enables features related to geospatial data discovery. Setting this variable to `true` will trigger geodata
9898
mode. Note that this is currently intended _only_ for the geodata app and
9999
may have unexpected consequences if applied to other TIMDEX UI apps.
100+
- `FEATURE_SIMULATE_SEARCH_LATENCY`: DO NOT SET IN PRODUCTION. Set to ensure a minimum of a one second delay in returning search results. Useful to see spinners/loaders. Only introduces delay for results that take less than one second to complete.
100101
- `FILTER_ACCESS_TO_FILES`: The name to use instead of "Access to files" for that filter / aggregation.
101102
- `FILTER_CONTENT_TYPE`: The name to use instead of "Content type" for that filter / aggregation.
102103
- `FILTER_CONTRIBUTOR`: The name to use instead of "Contributor" for that filter / aggregation.

app/controllers/search_controller.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
class SearchController < ApplicationController
22
before_action :validate_q!, only: %i[results]
33
before_action :set_active_tab, only: %i[results]
4+
around_action :sleep_if_too_fast, only: %i[results]
45

56
before_action :validate_geobox_presence!, only: %i[results]
67
before_action :validate_geobox_range!, only: %i[results]
@@ -30,6 +31,25 @@ def results
3031

3132
private
3233

34+
# Sleep to simulate latency for testing loading indicators when responses are fast
35+
def sleep_if_too_fast
36+
start_time = Time.now
37+
38+
yield
39+
40+
end_time = Time.now
41+
duration = end_time - start_time
42+
43+
return unless Feature.enabled?(:simulate_search_latency)
44+
45+
Rails.logger.debug "Action #{action_name} from controller #{controller_name} took #{duration.round(2)} seconds to execute."
46+
47+
return unless duration < 1
48+
49+
Rails.logger.debug("Sleeping for #{1 - duration}")
50+
sleep(1 - duration)
51+
end
52+
3353
def load_gdt_results
3454
query = QueryBuilder.new(@enhanced_query).query
3555

app/javascript/loading_spinner.js

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,35 @@ document.addEventListener('turbo:frame-render', function(event) {
88
}
99
// Clear the pending action
1010
window.pendingFocusAction = null;
11-
}
11+
};
12+
13+
if (window.pendingFocusAction === 'tab') {
14+
// console.log("Tab change detected - focusing on first result");
15+
16+
const urlParams = new URLSearchParams(window.location.search);
17+
const queryParam = urlParams.get('tab');
18+
const searchInput = document.querySelector('input[name="tab"]');
19+
20+
// update hidden form element to ensure correct tab is used for subsequent searches
21+
if (searchInput && queryParam != null) {
22+
searchInput.value = queryParam;
23+
// console.log(`Updated tab input value to: ${queryParam}`);
24+
}
25+
26+
// update active tab styling
27+
// remove active class from all tabs
28+
document.querySelectorAll('.tab-link').forEach((tab) => {
29+
tab.classList.remove('active');
30+
});
31+
// add active class to current tab
32+
const currentTabLink = document.querySelector(`.tab-link[href*="tab=${queryParam}"]`);
33+
if (currentTabLink) {
34+
currentTabLink.classList.add('active');
35+
}
36+
37+
// Clear the pending action
38+
window.pendingFocusAction = null;
39+
};
1240
});
1341

1442
document.addEventListener('click', function(event) {
@@ -20,4 +48,26 @@ document.addEventListener('click', function(event) {
2048
window.scrollTo({ top: 0, behavior: 'smooth' });
2149
window.pendingFocusAction = 'pagination';
2250
}
23-
});
51+
52+
// Handle tab clicks
53+
if (clickedElement.closest('.tab-navigation')) {
54+
window.scrollTo({ top: 0, behavior: 'smooth' });
55+
window.pendingFocusAction = 'tab';
56+
}
57+
});
58+
59+
// On Turbo Frame render, update the search input value to match the current URL parameter
60+
// This ensures that after using the back button the search input reflects the correct query
61+
document.addEventListener('turbo:load', function(event) {
62+
// update form element name 'q' to use current url paramater `q`
63+
// console.log(`turbo:frame-render event detected for frame: ${event.target.id}`);
64+
const urlParams = new URLSearchParams(window.location.search);
65+
const queryParam = urlParams.get('q');
66+
const searchInput = document.querySelector('input[name="q"]');
67+
if (searchInput && queryParam != null) {
68+
searchInput.value = queryParam;
69+
// console.log(`Updated search input value to: ${queryParam}`);
70+
}
71+
});
72+
73+

app/models/feature.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
#
3434
class Feature
3535
# List of all valid features in the application
36-
VALID_FEATURES = %i[geodata boolean_picker].freeze
36+
VALID_FEATURES = %i[geodata boolean_picker simulate_search_latency].freeze
3737

3838
# Check if a feature is enabled by name
3939
#

app/views/search/_source_tabs.html.erb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
<div id="tabs" class="tab-navigation top-space">
33
<%= link_to "Primo", results_path(params.permit(:q, :per_page, :page).merge(tab: 'primo')),
44
class: "tab-link #{'active' if @active_tab == 'primo'}",
5-
data: { turbo_frame: "_top", turbo_action: "advance" } %>
5+
data: { turbo_frame: "search-results", turbo_action: "advance" } %>
66
<%= link_to "TIMDEX", results_path(params.permit(:q, :per_page, :page).merge(tab: 'timdex')),
77
class: "tab-link #{'active' if @active_tab == 'timdex'}",
8-
data: { turbo_frame: "_top", turbo_action: "advance" } %>
8+
data: { turbo_frame: "search-results", turbo_action: "advance" } %>
99
</div>
1010

0 commit comments

Comments
 (0)