From 1d40efc9d495d28db3949818ee350e9518b7eac9 Mon Sep 17 00:00:00 2001 From: Marwin Hochfelsner <50826859+hlfan@users.noreply.github.com> Date: Mon, 20 Jul 2026 01:14:14 +0000 Subject: [PATCH] Use Turbo frames for sidebar loading --- app/assets/javascripts/index.js | 62 ++++++++----------- app/assets/stylesheets/common.scss | 5 ++ app/controllers/application_controller.rb | 5 +- app/views/layouts/map.html.erb | 6 +- app/views/layouts/xhr.html.erb | 6 +- .../controllers/changesets_controller_test.rb | 6 +- test/controllers/notes_controller_test.rb | 2 +- test/controllers/searches_controller_test.rb | 4 +- test/controllers/site_controller_test.rb | 2 +- test/test_helper.rb | 4 +- 10 files changed, 52 insertions(+), 50 deletions(-) diff --git a/app/assets/javascripts/index.js b/app/assets/javascripts/index.js index 1ec154b85..0a9e4ae14 100644 --- a/app/assets/javascripts/index.js +++ b/app/assets/javascripts/index.js @@ -25,45 +25,37 @@ $(function () { }); OSM.loadSidebarContent = function (path) { - const atomSelector = "link[type=\"application/atom+xml\"]"; - map.setSidebarOverlaid(false); - $("#sidebar_loader").prop("hidden", false).addClass("delayed-fade-in"); - - // Prevent caching the XHR response as a full-page URL - // https://github.com/openstreetmap/openstreetmap-website/issues/5663 - const queryParamSeparator = path.includes("?") ? "&" : "?"; - const xhrPath = `${path}${queryParamSeparator}xhr=1`; - - $("#sidebar_content") - .empty(); - - return fetch(xhrPath, { headers: { "accept": "text/html", "x-requested-with": "XMLHttpRequest" } }) - .then(response => { - $("#flash").empty(); - $("#sidebar_loader").removeClass("delayed-fade-in").prop("hidden", true); - - return response.text().then(html => ({ response, html })); - }) - .then(({ response, html }) => { - const content = $($.parseHTML(html)); - - const title = response.headers.get("X-Page-Title"); - if (title) document.title = decodeURIComponent(title); - - $("head").find(atomSelector).remove(); - - $("head").append(content.filter(atomSelector)); - - $("#sidebar_content").html(content.not(atomSelector)); - - if (!response.ok) { - throw new Error(`HTTP Error ${response.status} ${response.statusText}`); - } - }); + return new Promise((resolve, reject) => { + $("#sidebar_content_frame") + .one("turbo:frame-render", event => { + const response = event.originalEvent.detail.fetchResponse.response; + + const title = response.headers.get("X-Page-Title"); + if (title) document.title = decodeURIComponent(title); + + if (response.ok) { + resolve(); + } else { + reject(new Error(`HTTP Error ${response.status} ${response.statusText}`)); + } + }) + .prop("src", path); + }); }; + $("#sidebar_content_frame") + .on("turbo:before-fetch-response", () => $("#flash").empty()) + .on("turbo:before-frame-render", event => { + const atomSelector = "link[type='application/atom+xml']"; + $("head").find(atomSelector).remove(); + $("head").append( + $(event.originalEvent.detail.newFrame) + .find(atomSelector) + .detach()); + }); + const token = $("head").data("oauthToken"); if (token) OSM.oauth = { authorization: "Bearer " + token }; diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index 59fd33b22..7fe92baae 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -237,6 +237,11 @@ header nav { } } + #sidebar_loader:has(+ #sidebar_content turbo-frame:not([busy])), + #sidebar_content turbo-frame[busy] { + display: none; + } + #content:not(.overlay-sidebar) :is(.welcome, #banner) { @extend .d-none; } diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 1440f67eb..3e6fa3a0a 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -208,7 +208,7 @@ class ApplicationController < ActionController::Base I18n.locale = Locale.available.preferred(preferred_languages) - response.headers["Vary"] = "Accept-Language" + response.headers["Vary"] = response.headers["Vary"].present? ? "#{response.headers['Vary']}, Accept-Language" : "Accept-Language" response.headers["Content-Language"] = I18n.locale.to_s end @@ -263,7 +263,8 @@ class ApplicationController < ActionController::Base flash.now[:warning] = { :partial => "layouts/offline_flash" } unless api_status == "online" - request.xhr? ? "xhr" : "map" + response.headers["Vary"] = response.headers["Vary"].present? ? "#{response.headers['Vary']}, Turbo-Frame" : "Turbo-Frame" + turbo_frame_request? ? "xhr" : "map" end def preferred_editor diff --git a/app/views/layouts/map.html.erb b/app/views/layouts/map.html.erb index 294f31761..89c77f654 100644 --- a/app/views/layouts/map.html.erb +++ b/app/views/layouts/map.html.erb @@ -20,10 +20,12 @@ <%= render :partial => "layouts/sidebar_close" %> -
+ <% unless current_user %> diff --git a/app/views/layouts/xhr.html.erb b/app/views/layouts/xhr.html.erb index ab33aae8d..95b4d8ca1 100644 --- a/app/views/layouts/xhr.html.erb +++ b/app/views/layouts/xhr.html.erb @@ -1,2 +1,4 @@ -<%= content_for :auto_discovery_link_tag %> -<%= yield %> +