From d656bd8704b50d1bf9c49e5fa16b6de159cafe8c Mon Sep 17 00:00:00 2001 From: Armin Kirchner Date: Fri, 6 Jun 2025 10:08:25 +0200 Subject: [PATCH 1/3] Chore: Migrate Tubolinks to Turbo Trubolinks has been replaced by Turbo. The Turbolinks library has been achieved. Resolves #2952 --- Gemfile | 2 +- Gemfile.lock | 7 +----- app/assets/javascripts/application.js | 1 - app/assets/javascripts/base.js | 7 ++---- .../javascripts/bootstrap-dropdown-submenu.js | 2 +- .../javascripts/channels/la_exercises.js | 2 +- .../channels/pg_matching_channel.js | 2 +- .../channels/synchronized_editor_channel.js | 2 +- app/assets/javascripts/codeharbor_link.js | 2 +- app/assets/javascripts/community_solution.js | 2 +- app/assets/javascripts/dashboard.js | 2 +- app/assets/javascripts/editor.js | 4 +-- app/assets/javascripts/editor/editor.js.erb | 9 ++----- app/assets/javascripts/error_templates.js | 2 +- .../javascripts/exercise_collections.js | 2 +- app/assets/javascripts/exercise_graphs.js | 2 +- app/assets/javascripts/exercises.js | 4 +-- app/assets/javascripts/external_users.js | 2 +- app/assets/javascripts/file_types.js | 2 +- app/assets/javascripts/forms.js | 4 +-- app/assets/javascripts/markdown_editor.js | 2 +- app/assets/javascripts/programming_groups.js | 2 +- .../javascripts/request_for_comments.js | 2 +- app/assets/javascripts/shell.js | 2 +- .../statistics_activity_history.js | 2 +- app/assets/javascripts/statistics_graphs.js | 2 +- .../javascripts/submission_statistics.js | 4 +-- app/assets/javascripts/working_time_graphs.js | 2 +- app/javascript/application.js | 2 ++ app/javascript/tooltip.js | 25 +++++++++++++++++++ app/javascript/webauthn.js | 2 +- app/views/admin/dashboard/show.html.slim | 2 +- .../application/_locale_selector.html.slim | 2 +- app/views/application/_navigation.html.slim | 4 +-- app/views/community_solutions/edit.html.slim | 2 +- .../execution_environments/_form.html.slim | 2 +- .../execution_environments/show.html.slim | 2 +- .../statistics.html.slim | 2 +- .../exercise_collections/_form.html.slim | 2 +- app/views/exercise_collections/show.html.slim | 2 +- .../exercise_collections/statistics.html.slim | 2 +- app/views/exercises/_form.html.slim | 2 +- app/views/exercises/_tips_content.html.slim | 2 +- app/views/exercises/implement.html.slim | 2 +- app/views/exercises/index.html.slim | 6 ++--- app/views/exercises/show.html.slim | 6 ++--- app/views/exercises/statistics.html.slim | 2 +- .../exercises/study_group_dashboard.html.slim | 2 +- app/views/layouts/application.html.slim | 8 +++--- app/views/programming_groups/index.html.slim | 2 +- app/views/proxy_exercises/_form.html.slim | 2 +- app/views/proxy_exercises/index.html.slim | 2 +- .../statistics/activity_history.html.slim | 2 +- app/views/statistics/graphs.html.slim | 2 +- app/views/submissions/show.html.slim | 2 +- app/views/tips/_form.html.slim | 2 +- app/views/tips/show.html.slim | 2 +- .../new.html.slim | 2 +- app/views/webauthn_credentials/new.html.slim | 2 +- config/locales/de/programming_group.yml | 2 +- config/locales/en/programming_group.yml | 2 +- lib/assets/javascripts/color_mode_picker.js | 2 +- lib/assets/javascripts/flash.js | 2 +- package.json | 1 + spec/support/wait_for_ajax.rb | 7 ++++++ yarn.lock | 25 +++++++++++++++++++ 66 files changed, 134 insertions(+), 88 deletions(-) create mode 100644 app/javascript/tooltip.js diff --git a/Gemfile b/Gemfile index 776600a62..664cc9848 100644 --- a/Gemfile +++ b/Gemfile @@ -53,7 +53,7 @@ gem 'sprockets-rails' gem 'telegraf' gem 'terser', require: false gem 'tubesock', github: 'openhpi/tubesock' -gem 'turbolinks' +gem 'turbo-rails' gem 'webauthn' gem 'zxcvbn-ruby', require: 'zxcvbn' diff --git a/Gemfile.lock b/Gemfile.lock index 4eb59394a..4da17ac14 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -617,9 +617,6 @@ GEM turbo-rails (2.0.13) actionpack (>= 7.1.0) railties (>= 7.1.0) - turbolinks (5.2.1) - turbolinks-source (~> 5.2) - turbolinks-source (5.2.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) unicode-display_width (3.1.4) @@ -749,7 +746,7 @@ DEPENDENCIES telegraf terser tubesock! - turbolinks + turbo-rails web-console webauthn webmock @@ -992,8 +989,6 @@ CHECKSUMS tpm-key_attestation (0.14.0) sha256=d05cc52b397f89c36a7307407e0e84d3ea1c7afce50e0a70b146f8ab17d2bf4b tubesock (0.2.9) turbo-rails (2.0.13) sha256=c40ac0a3ccd57c129925c8ac524a5dfd1e17fad080906e2d32135721a8bba22f - turbolinks (5.2.1) sha256=5fea5889c4e2a78a5bd9abda3860c565342b50c6e2593697d5558a08e15cce9c - turbolinks-source (5.2.0) sha256=362a41fa851a22b0f15cf8f944b6c7c5788f645dc1f61ae25478bb25c3bc85d4 tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b unicode-display_width (3.1.4) sha256=8caf2af1c0f2f07ec89ef9e18c7d88c2790e217c482bfc78aaa65eadd5415ac1 unicode-emoji (4.0.4) sha256=2c2c4ef7f353e5809497126285a50b23056cc6e61b64433764a35eff6c36532a diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index ba76b2e15..123169a0b 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -10,7 +10,6 @@ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details // about supported directives. // -//= require turbolinks //= require rails-timeago //= require locales/jquery.timeago.de.js // diff --git a/app/assets/javascripts/base.js b/app/assets/javascripts/base.js index 2a512a07a..8f5ea3379 100644 --- a/app/assets/javascripts/base.js +++ b/app/assets/javascripts/base.js @@ -4,7 +4,7 @@ Array.prototype.includes = function(element) { window.CodeOcean = { refresh: function() { - Turbolinks.visit(window.location.pathname); + Turbo.visit(window.location.pathname); } }; @@ -24,7 +24,7 @@ $.fn.scrollTo = function(selector) { }, ANIMATION_DURATION); }; -$(document).on('turbolinks:load', function() { +$(document).on('turbo:load', function() { // Update all CSRF tokens on the page to reduce InvalidAuthenticityToken errors // See https://github.com/rails/jquery-ujs/issues/456 for details $.rails.refreshCSRFTokens(); @@ -66,9 +66,6 @@ $(document).on('turbolinks:load', function() { }); } - // Enable all tooltips - $('[data-bs-toggle="tooltip"]').tooltip(); - // Enable sorttable again, as it is disabled otherwise by Turbolinks if (sorttable) { sorttable.init.done = false; diff --git a/app/assets/javascripts/bootstrap-dropdown-submenu.js b/app/assets/javascripts/bootstrap-dropdown-submenu.js index 38ad38540..5c57d9da6 100644 --- a/app/assets/javascripts/bootstrap-dropdown-submenu.js +++ b/app/assets/javascripts/bootstrap-dropdown-submenu.js @@ -1,4 +1,4 @@ -$(document).on('turbolinks:load', function() { +$(document).on('turbo:load', function() { var subMenusSelector = 'ul.dropdown-menu [data-bs-toggle=dropdown]'; diff --git a/app/assets/javascripts/channels/la_exercises.js b/app/assets/javascripts/channels/la_exercises.js index bfb7e0e20..98c2eee16 100644 --- a/app/assets/javascripts/channels/la_exercises.js +++ b/app/assets/javascripts/channels/la_exercises.js @@ -1,4 +1,4 @@ -$(document).on('turbolinks:load', function() { +$(document).on('turbo:load', function() { if ($.isController('exercises') && $('.teacher_dashboard').isPresent()) { const exercise_id = $('.teacher_dashboard').data().exerciseId; diff --git a/app/assets/javascripts/channels/pg_matching_channel.js b/app/assets/javascripts/channels/pg_matching_channel.js index f07fe4fde..411e56a0a 100644 --- a/app/assets/javascripts/channels/pg_matching_channel.js +++ b/app/assets/javascripts/channels/pg_matching_channel.js @@ -1,4 +1,4 @@ -$(document).on('turbolinks:load', function () { +$(document).on('turbo:load', function () { if ($.isController('programming_groups') && window.location.pathname.includes('programming_groups/new')) { const matching_page = $('#matching'); diff --git a/app/assets/javascripts/channels/synchronized_editor_channel.js b/app/assets/javascripts/channels/synchronized_editor_channel.js index 6f9093280..3b1f65e20 100644 --- a/app/assets/javascripts/channels/synchronized_editor_channel.js +++ b/app/assets/javascripts/channels/synchronized_editor_channel.js @@ -1,4 +1,4 @@ -$(document).on('turbolinks:load', function () { +$(document).on('turbo:load', function () { if (window.location.pathname.includes('/implement')) { var editor = $('#editor'); diff --git a/app/assets/javascripts/codeharbor_link.js b/app/assets/javascripts/codeharbor_link.js index c63e8b60a..c31414f13 100644 --- a/app/assets/javascripts/codeharbor_link.js +++ b/app/assets/javascripts/codeharbor_link.js @@ -1,4 +1,4 @@ -$(document).on('turbolinks:load', function() { +$(document).on('turbo:load', function() { if($.isController('codeharbor_links')) { if ($('.edit_codeharbor_link, .new_codeharbor_link').isPresent()) { diff --git a/app/assets/javascripts/community_solution.js b/app/assets/javascripts/community_solution.js index dd3280bb6..382c0faf3 100644 --- a/app/assets/javascripts/community_solution.js +++ b/app/assets/javascripts/community_solution.js @@ -1,4 +1,4 @@ -$(document).on('turbolinks:load', function() { +$(document).on('turbo:load', function() { if ($.isController('community_solutions') && $('#community-solution-editor').isPresent()) { CodeOceanEditor.sendEvents = false; diff --git a/app/assets/javascripts/dashboard.js b/app/assets/javascripts/dashboard.js index e8c434442..d8fe3c948 100644 --- a/app/assets/javascripts/dashboard.js +++ b/app/assets/javascripts/dashboard.js @@ -1,4 +1,4 @@ -$(document).on('turbolinks:load', function() { +$(document).on('turbo:load', function() { var CHART_START = window.vis ? vis.moment().add(-1, 'minute') : undefined; var DEFAULT_REFRESH_INTERVAL = 5000; diff --git a/app/assets/javascripts/editor.js b/app/assets/javascripts/editor.js index 28e943353..0635ce3f4 100644 --- a/app/assets/javascripts/editor.js +++ b/app/assets/javascripts/editor.js @@ -1,4 +1,4 @@ -$(document).on('turbolinks:load', function(event) { +$(document).on('turbo:load', function(event) { //Merge all editor components. $.extend( @@ -13,7 +13,7 @@ $(document).on('turbolinks:load', function(event) { CodeOceanEditorRequestForComments ); - if ($('#editor').isPresent() && CodeOceanEditor && event.originalEvent.data.url.includes("/implement")) { + if ($('#editor').isPresent() && CodeOceanEditor && event.originalEvent.detail.url.includes("/implement")) { // This call will (amon other things) initializeEditors and load the content except for the last line // It must not be called during page navigation. Otherwise, content will be duplicated! // Search for insertFullLines and Turbolinks reload / cache control diff --git a/app/assets/javascripts/editor/editor.js.erb b/app/assets/javascripts/editor/editor.js.erb index e5f65eea8..744ca9e24 100644 --- a/app/assets/javascripts/editor/editor.js.erb +++ b/app/assets/javascripts/editor/editor.js.erb @@ -935,10 +935,6 @@ var CodeOceanEditor = { $('#output_sidebar').removeClass('output-col').addClass('output-col-collapsed'); }, - initializeSideBarTooltips: function () { - $('[data-bs-toggle="tooltip"]').tooltip() - }, - initializeDescriptionToggle: function () { $('#exercise-headline').on('click', this.toggleDescriptionCard.bind(this)); $('a#toggle').on('click', this.toggleDescriptionCard.bind(this)); @@ -1095,7 +1091,6 @@ var CodeOceanEditor = { this.initializeSideBarCollapse(); this.initializeOutputBarToggle(); this.initializeDescriptionToggle(); - this.initializeSideBarTooltips(); this.initializeInterventionTimer(); this.initPrompt(); this.renderScore(); @@ -1105,10 +1100,10 @@ var CodeOceanEditor = { this.initializeDeadlines(); CodeOceanEditorTips.initializeEventHandlers(); - window.addEventListener("turbolinks:before-render", App.synchronized_editor?.disconnect.bind(App.synchronized_editor)); + window.addEventListener("turbo:before-render", App.synchronized_editor?.disconnect.bind(App.synchronized_editor)); window.addEventListener("beforeunload", App.synchronized_editor?.disconnect.bind(App.synchronized_editor)); - window.addEventListener("turbolinks:before-render", this.autosaveIfChanged.bind(this)); + window.addEventListener("turbo:before-render", this.autosaveIfChanged.bind(this)); window.addEventListener("beforeunload", this.autosaveIfChanged.bind(this)); // create autosave when the editor is opened the first time this.autosave(); diff --git a/app/assets/javascripts/error_templates.js b/app/assets/javascripts/error_templates.js index d98840a77..81dc5b546 100644 --- a/app/assets/javascripts/error_templates.js +++ b/app/assets/javascripts/error_templates.js @@ -1,4 +1,4 @@ -$(document).on('turbolinks:load', function() { +$(document).on('turbo:load', function() { if ($.isController('error_templates')) { const button = $('#add-attribute').find('button') button.on('click', function () { diff --git a/app/assets/javascripts/exercise_collections.js b/app/assets/javascripts/exercise_collections.js index d89bcd271..18fb1716b 100644 --- a/app/assets/javascripts/exercise_collections.js +++ b/app/assets/javascripts/exercise_collections.js @@ -1,4 +1,4 @@ -$(document).on('turbolinks:load', function() { +$(document).on('turbo:load', function() { if ($.isController('exercise_collections')) { var dataElement = $('#data'); var exerciseList = $('#exercise-list'); diff --git a/app/assets/javascripts/exercise_graphs.js b/app/assets/javascripts/exercise_graphs.js index 18709969a..8d14e30d7 100644 --- a/app/assets/javascripts/exercise_graphs.js +++ b/app/assets/javascripts/exercise_graphs.js @@ -1,4 +1,4 @@ -$(document).on('turbolinks:load', function() { +$(document).on('turbo:load', function() { // /exercises/38/statistics good for testing if ($.isController('exercises') && $('.graph-functions-2').isPresent()) { diff --git a/app/assets/javascripts/exercises.js b/app/assets/javascripts/exercises.js index d7df46aa0..7d117936d 100644 --- a/app/assets/javascripts/exercises.js +++ b/app/assets/javascripts/exercises.js @@ -1,4 +1,4 @@ -$(document).on('turbolinks:load', function () { +$(document).on('turbo:load', function () { const TAB_KEY_CODE = 9; let execution_environments; @@ -571,4 +571,4 @@ $(document).on('turbolinks:load', function () { } -}); \ No newline at end of file +}); diff --git a/app/assets/javascripts/external_users.js b/app/assets/javascripts/external_users.js index f97436e31..2e9e91266 100644 --- a/app/assets/javascripts/external_users.js +++ b/app/assets/javascripts/external_users.js @@ -1,4 +1,4 @@ -$(document).on('turbolinks:load', function() { +$(document).on('turbo:load', function() { const grid = $('#tag-grid'); if ($.isController('external_users') && grid.isPresent()) { diff --git a/app/assets/javascripts/file_types.js b/app/assets/javascripts/file_types.js index 2133be370..d37a96fe4 100644 --- a/app/assets/javascripts/file_types.js +++ b/app/assets/javascripts/file_types.js @@ -1,4 +1,4 @@ -$(document).on('turbolinks:load', function() { +$(document).on('turbo:load', function() { if ($.isController('file_types')) { const select_tag = $('#file_type_editor_mode'); diff --git a/app/assets/javascripts/forms.js b/app/assets/javascripts/forms.js index 86b1b211c..4e47b9e25 100644 --- a/app/assets/javascripts/forms.js +++ b/app/assets/javascripts/forms.js @@ -1,4 +1,4 @@ -$(document).on('turbolinks:load', function() { +$(document).on('turbo:load', function() { var CHOSEN_OPTIONS = { allow_single_deselect: true, disable_search_threshold: 5, @@ -50,6 +50,6 @@ $(document).on('turbolinks:load', function() { }); // Remove some elements before going back to an older site. Otherwise, they might not work. -$(document).on('turbolinks:before-cache', function() { +$(document).on('turbo:before-cache', function() { $('.chosen-container').remove(); }); diff --git a/app/assets/javascripts/markdown_editor.js b/app/assets/javascripts/markdown_editor.js index 7575aae41..0375ae147 100644 --- a/app/assets/javascripts/markdown_editor.js +++ b/app/assets/javascripts/markdown_editor.js @@ -192,7 +192,7 @@ const setResizeBtn = (formInput, editor) => { }); }; -$(document).on("turbolinks:load", function () { +$(document).on("turbo:load", function () { initializeMarkdownEditors(); disableImageUpload(); }); diff --git a/app/assets/javascripts/programming_groups.js b/app/assets/javascripts/programming_groups.js index e49ce5055..315a7cf75 100644 --- a/app/assets/javascripts/programming_groups.js +++ b/app/assets/javascripts/programming_groups.js @@ -26,7 +26,7 @@ var ProgrammingGroups = { } }; -$(document).on('turbolinks:load', function () { +$(document).on('turbo:load', function () { const modal = $('#modal-info-pair-programming'); if (modal.isPresent()) { ProgrammingGroups.initializeEventHandler(); diff --git a/app/assets/javascripts/request_for_comments.js b/app/assets/javascripts/request_for_comments.js index d0db56bc0..7358ad20a 100644 --- a/app/assets/javascripts/request_for_comments.js +++ b/app/assets/javascripts/request_for_comments.js @@ -1,4 +1,4 @@ -$(document).on('turbolinks:load', function () { +$(document).on('turbo:load', function () { const exerciseCaption = $('#exercise_caption'); if (!$.isController('request_for_comments') || !exerciseCaption.isPresent()) { diff --git a/app/assets/javascripts/shell.js b/app/assets/javascripts/shell.js index d58426e34..efd4e5507 100644 --- a/app/assets/javascripts/shell.js +++ b/app/assets/javascripts/shell.js @@ -1,4 +1,4 @@ -$(document).on('turbolinks:load', function () { +$(document).on('turbo:load', function () { const ENTER_KEY_CODE = 13; const clearOutput = function () { diff --git a/app/assets/javascripts/statistics_activity_history.js b/app/assets/javascripts/statistics_activity_history.js index 7126d428a..7c9d3c927 100644 --- a/app/assets/javascripts/statistics_activity_history.js +++ b/app/assets/javascripts/statistics_activity_history.js @@ -1,4 +1,4 @@ -$(document).on('turbolinks:load', function() { +$(document).on('turbo:load', function() { function manageActivityHistory(prefix) { var containerId = prefix + '-activity-history'; diff --git a/app/assets/javascripts/statistics_graphs.js b/app/assets/javascripts/statistics_graphs.js index bda79fa6d..8016eb68f 100644 --- a/app/assets/javascripts/statistics_graphs.js +++ b/app/assets/javascripts/statistics_graphs.js @@ -1,4 +1,4 @@ -$(document).on('turbolinks:load', function() { +$(document).on('turbo:load', function() { if ($.isController('statistics') && $('.graph#user-activity').isPresent()) { function manageGraph(containerId, url, refreshAfter) { diff --git a/app/assets/javascripts/submission_statistics.js b/app/assets/javascripts/submission_statistics.js index 8010af4ac..49f1bed4b 100644 --- a/app/assets/javascripts/submission_statistics.js +++ b/app/assets/javascripts/submission_statistics.js @@ -1,4 +1,4 @@ -$(document).on('turbolinks:load', function(event) { +$(document).on('turbo:load', function(event) { var currentSubmission = 0; var active_file = undefined; var fileTrees = []; @@ -60,7 +60,7 @@ $(document).on('turbolinks:load', function(event) { $(fileTrees[index]).show(); }; - if ($.isController('exercises') && $('#timeline').isPresent() && event.originalEvent.data.url.includes("/statistics")) { + if ($.isController('exercises') && $('#timeline').isPresent() && event.originalEvent.detail.url.includes("/statistics")) { var slider = $('#submissions-slider>input'); var submissions = $('#data').data('submissions'); diff --git a/app/assets/javascripts/working_time_graphs.js b/app/assets/javascripts/working_time_graphs.js index 7d09169df..fa2acdbc2 100644 --- a/app/assets/javascripts/working_time_graphs.js +++ b/app/assets/javascripts/working_time_graphs.js @@ -1,4 +1,4 @@ -$(document).on('turbolinks:load', function() { +$(document).on('turbo:load', function() { // /38/statistics good for testing if ($.isController('exercises') && $('.working-time-graphs').isPresent()) { diff --git a/app/javascript/application.js b/app/javascript/application.js index 03bda112e..4622512fe 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -8,6 +8,7 @@ // layout file, like app/views/layouts/application.html.slim // JS +import '@hotwired/turbo-rails' import 'jquery'; import 'jquery-ujs' import * as bootstrap from 'bootstrap/dist/js/bootstrap.bundle'; @@ -17,6 +18,7 @@ import * as _ from 'underscore'; import * as d3 from 'd3'; import * as Sentry from '@sentry/browser'; import 'sorttable'; +import 'tooltip'; window.bootstrap = bootstrap; // Publish bootstrap in global namespace window._ = _; // Publish underscore's `_` in global namespace window.d3 = d3; // Publish d3 in global namespace diff --git a/app/javascript/tooltip.js b/app/javascript/tooltip.js new file mode 100644 index 000000000..d56cea401 --- /dev/null +++ b/app/javascript/tooltip.js @@ -0,0 +1,25 @@ +const tooltipMap = new WeakMap(); + +function manageTooltips() { + const selector = '[data-bs-toggle="tooltip"]'; + const currentElements = new Set(document.querySelectorAll(selector)); + + // Dispose tooltips for elements no longer in the DOM + for (const [element, tooltipInstance] of tooltipMap.entries()) { + if (!currentElements.has(element)) { + tooltipInstance.dispose(); + tooltipMap.delete(element); + } + } + + // Initialize tooltips for new elements + currentElements.forEach((element) => { + if (!tooltipMap.has(element)) { + const instance = new bootstrap.Tooltip(element); + tooltipMap.set(element, instance); + } + }); +} + +window.addEventListener('turbo:load', manageTooltips); +window.addEventListener('turbo:frame-load', manageTooltips); diff --git a/app/javascript/webauthn.js b/app/javascript/webauthn.js index ea9400082..6f0c8ce54 100644 --- a/app/javascript/webauthn.js +++ b/app/javascript/webauthn.js @@ -23,7 +23,7 @@ async function getCredential(publicKey) { return await get(options); } -$(document).on('turbolinks:load', function() { +$(document).on('turbo:load', function() { if ($.isController('webauthn_credentials')) { form = $('form#new_webauthn_credential'); credentialMethod = createCredential; diff --git a/app/views/admin/dashboard/show.html.slim b/app/views/admin/dashboard/show.html.slim index a1ac431ee..14284e603 100644 --- a/app/views/admin/dashboard/show.html.slim +++ b/app/views/admin/dashboard/show.html.slim @@ -1,7 +1,7 @@ - content_for :head do // Force a full page reload, see https://github.com/turbolinks/turbolinks/issues/326. Otherwise, the global variable `vis` might be uninitialized in the assets (race condition) - meta name='turbolinks-visit-control' content='reload' + meta name='turbo-visit-control' content='reload' - append_javascript_pack_tag('vis') - append_stylesheet_pack_tag('vis') diff --git a/app/views/application/_locale_selector.html.slim b/app/views/application/_locale_selector.html.slim index 3f429b616..1b595c7ba 100644 --- a/app/views/application/_locale_selector.html.slim +++ b/app/views/application/_locale_selector.html.slim @@ -4,4 +4,4 @@ li.nav-item.dropdown span.caret ul.dropdown-menu.p-0.mt-1 role='menu' - I18n.available_locales.sort_by {|locale| t("locales.#{locale}") }.each do |locale| - li = link_to(t("locales.#{locale}"), AuthenticatedUrlHelper.add_query_parameters(request.url, locale:), 'data-turbolinks': 'false', class: 'dropdown-item') + li = link_to(t("locales.#{locale}"), AuthenticatedUrlHelper.add_query_parameters(request.url, locale:), 'data-turbo': 'false', class: 'dropdown-item') diff --git a/app/views/application/_navigation.html.slim b/app/views/application/_navigation.html.slim index 337b64ede..b517e3f58 100644 --- a/app/views/application/_navigation.html.slim +++ b/app/views/application/_navigation.html.slim @@ -6,8 +6,8 @@ span.caret ul.dropdown-menu.p-0.mt-1 role='menu' - if current_user.admin? - li = link_to(t('breadcrumbs.dashboard.show'), admin_dashboard_path, class: 'dropdown-item', 'data-turbolinks': 'false') if policy(%i[admin dashboard]).show? - li = link_to(t('breadcrumbs.rails_admin.show'), rails_admin.dashboard_path, class: 'dropdown-item', 'data-turbolinks': 'false') if policy(%i[admin dashboard]).show? + li = link_to(t('breadcrumbs.dashboard.show'), admin_dashboard_path, class: 'dropdown-item', 'data-turbo': 'false') if policy(%i[admin dashboard]).show? + li = link_to(t('breadcrumbs.rails_admin.show'), rails_admin.dashboard_path, class: 'dropdown-item', 'data-turbo': 'false') if policy(%i[admin dashboard]).show? li = link_to(t('breadcrumbs.statistics.show'), statistics_path, class: 'dropdown-item') if policy(:statistics).show? li.dropdown-divider role='separator' = render('navigation_submenu', title: Exercise.model_name.human(count: :other), diff --git a/app/views/community_solutions/edit.html.slim b/app/views/community_solutions/edit.html.slim index a8f43e2c8..2463668df 100644 --- a/app/views/community_solutions/edit.html.slim +++ b/app/views/community_solutions/edit.html.slim @@ -1,6 +1,6 @@ - content_for :head do // Force a full page reload, see https://github.com/turbolinks/turbolinks/issues/326. Otherwise, code might not be highlighted correctly (race condition) - meta name='turbolinks-visit-control' content='reload' + meta name='turbo-visit-control' content='reload' == render 'form' diff --git a/app/views/execution_environments/_form.html.slim b/app/views/execution_environments/_form.html.slim index 081dd113a..3fd5a45d4 100644 --- a/app/views/execution_environments/_form.html.slim +++ b/app/views/execution_environments/_form.html.slim @@ -1,7 +1,7 @@ - content_for :head do // Force a full page reload, see https://github.com/turbolinks/turbolinks/issues/326. Otherwise, code might not be highlighted correctly (race condition) - meta name='turbolinks-visit-control' content='reload' + meta name='turbo-visit-control' content='reload' - append_javascript_pack_tag('toast-ui') - append_stylesheet_pack_tag('toast-ui') diff --git a/app/views/execution_environments/show.html.slim b/app/views/execution_environments/show.html.slim index d70f13abb..f85b01f17 100644 --- a/app/views/execution_environments/show.html.slim +++ b/app/views/execution_environments/show.html.slim @@ -5,7 +5,7 @@ h1.d-inline-block = @execution_environment ul.dropdown-menu.dropdown-menu-end role='menu' li = link_to(t('execution_environments.index.synchronize.button'), sync_to_runner_management_execution_environment_path(@execution_environment), method: :post, class: 'dropdown-item') if policy(@execution_environment).sync_to_runner_management? li = link_to(t('execution_environments.index.shell'), shell_execution_environment_path(@execution_environment), class: 'dropdown-item') if policy(@execution_environment).shell? - li = link_to(t('shared.statistics'), statistics_execution_environment_path(@execution_environment), 'data-turbolinks': 'false', class: 'dropdown-item') if policy(@execution_environment).statistics? + li = link_to(t('shared.statistics'), statistics_execution_environment_path(@execution_environment), 'data-turbo': 'false', class: 'dropdown-item') if policy(@execution_environment).statistics? li = link_to(t('shared.destroy'), @execution_environment, data: {confirm: t('shared.confirm_destroy')}, method: :delete, class: 'dropdown-item') if policy(@execution_environment).destroy? = row(label: 'execution_environment.name', value: @execution_environment.name) diff --git a/app/views/execution_environments/statistics.html.slim b/app/views/execution_environments/statistics.html.slim index 0266d88e9..a98fd44dc 100644 --- a/app/views/execution_environments/statistics.html.slim +++ b/app/views/execution_environments/statistics.html.slim @@ -21,7 +21,7 @@ h1 = @execution_environment - if wts then average_time = wts['average_time'] else 0 # rubocop:disable Lint/ElseLayout - if wts then stddev_time = wts['stddev_time'] else 0 # rubocop:disable Lint/ElseLayout tr - td = link_to_if policy(exercise).statistics?, exercise.title, controller: 'exercises', action: 'statistics', id: exercise.id, 'data-turbolinks': 'false' + td = link_to_if policy(exercise).statistics?, exercise.title, controller: 'exercises', action: 'statistics', id: exercise.id, 'data-turbo': 'false' td = us['contributors'] td = us['average_score'].to_f.round(4) td = us['maximum_score'].to_f.round(2) diff --git a/app/views/exercise_collections/_form.html.slim b/app/views/exercise_collections/_form.html.slim index 99a55f914..351437580 100644 --- a/app/views/exercise_collections/_form.html.slim +++ b/app/views/exercise_collections/_form.html.slim @@ -24,7 +24,7 @@ td span.fa-solid.fa-bars td = item.exercise.title - td = link_to(t('shared.show'), item.exercise, 'data-turbolinks': 'false') + td = link_to(t('shared.show'), item.exercise, 'data-turbo': 'false') td a.remove-exercise href='#' = t('shared.destroy') .d-none diff --git a/app/views/exercise_collections/show.html.slim b/app/views/exercise_collections/show.html.slim index 9ddf17bfe..b7a80dac0 100644 --- a/app/views/exercise_collections/show.html.slim +++ b/app/views/exercise_collections/show.html.slim @@ -25,4 +25,4 @@ h4.mt-4 = ExerciseCollection.human_attribute_name('exercises') td = link_to_if(policy(exercise).show?, exercise.title, exercise) td = link_to_if(exercise.execution_environment && policy(exercise.execution_environment).show?, exercise.execution_environment, exercise.execution_environment) td = link_to_if(exercise.user && policy(exercise.user).show?, exercise.user.displayname, exercise.user) - td = link_to(t('shared.statistics'), statistics_exercise_path(exercise), 'data-turbolinks': 'false') if policy(exercise).statistics? + td = link_to(t('shared.statistics'), statistics_exercise_path(exercise), 'data-turbo': 'false') if policy(exercise).statistics? diff --git a/app/views/exercise_collections/statistics.html.slim b/app/views/exercise_collections/statistics.html.slim index 66e8a960a..f76db18f8 100644 --- a/app/views/exercise_collections/statistics.html.slim +++ b/app/views/exercise_collections/statistics.html.slim @@ -48,4 +48,4 @@ h4.mt-4 = ExerciseCollection.human_attribute_name('exercises') td = exercise.submissions.send(:final).distinct.count(:contributor_id) td = exercise.finishers_percentage td = exercise.average_percentage - td = link_to(t('shared.statistics'), statistics_exercise_path(exercise), 'data-turbolinks': 'false') if policy(exercise).statistics? + td = link_to(t('shared.statistics'), statistics_exercise_path(exercise), 'data-turbo': 'false') if policy(exercise).statistics? diff --git a/app/views/exercises/_form.html.slim b/app/views/exercises/_form.html.slim index c9cebd087..45f2d6e6e 100644 --- a/app/views/exercises/_form.html.slim +++ b/app/views/exercises/_form.html.slim @@ -1,7 +1,7 @@ - content_for :head do // Force a full page reload, see https://github.com/turbolinks/turbolinks/issues/326. Otherwise, code might not be highlighted correctly (race condition) - meta name='turbolinks-visit-control' content='reload' + meta name='turbo-visit-control' content='reload' - append_javascript_pack_tag('sortable') - append_javascript_pack_tag('toast-ui') - append_stylesheet_pack_tag('toast-ui') diff --git a/app/views/exercises/_tips_content.html.slim b/app/views/exercises/_tips_content.html.slim index a67f6a02b..9edc89e2f 100644 --- a/app/views/exercises/_tips_content.html.slim +++ b/app/views/exercises/_tips_content.html.slim @@ -1,7 +1,7 @@ - content_for :head do // Force a full page reload, see https://github.com/turbolinks/turbolinks/issues/326. Otherwise, code might not be highlighted correctly (race condition) - meta name='turbolinks-visit-control' content='reload' + meta name='turbo-visit-control' content='reload' - append_javascript_pack_tag('highlight') - append_stylesheet_pack_tag('highlight') diff --git a/app/views/exercises/implement.html.slim b/app/views/exercises/implement.html.slim index bc8873e54..4e1c76112 100644 --- a/app/views/exercises/implement.html.slim +++ b/app/views/exercises/implement.html.slim @@ -1,7 +1,7 @@ - content_for :head do // Force a full page reload, see https://github.com/turbolinks/turbolinks/issues/326. Otherwise, lti_parameters might be nil - meta name='turbolinks-cache-control' content='no-cache' + meta name='turbo-cache-control' content='no-cache' #editor-column - unless @embed_options[:hide_exercise_description] diff --git a/app/views/exercises/index.html.slim b/app/views/exercises/index.html.slim index dac1b5f63..cf140e160 100644 --- a/app/views/exercises/index.html.slim +++ b/app/views/exercises/index.html.slim @@ -28,7 +28,7 @@ h1 = Exercise.model_name.human(count: :other) - @exercises.each do |exercise| tr data-id=exercise.id td.p-1.pt-2 - = link_to_if(policy(exercise).show?, exercise.title, exercise, 'data-turbolinks': 'false') + = link_to_if(policy(exercise).show?, exercise.title, exercise, 'data-turbo': 'false') - if exercise.internal_title.present? p.mb-0.text-muted i.fa-solid.fa-arrow-turn-up.fa-rotate-90 @@ -41,13 +41,13 @@ h1 = Exercise.model_name.human(count: :other) td.p-1.pt-2.public data-value=exercise.public? = symbol_for(exercise.public?) td.p-1.pt-2 = link_to(t('shared.edit'), edit_exercise_path(exercise)) if policy(exercise).edit? td.p-1.pt-2 = link_to(t('.implement'), implement_exercise_path(exercise)) if policy(exercise).implement? - td.p-1.pt-2 = link_to(t('shared.statistics'), statistics_exercise_path(exercise), 'data-turbolinks': 'false') if policy(exercise).statistics? + td.p-1.pt-2 = link_to(t('shared.statistics'), statistics_exercise_path(exercise), 'data-turbo': 'false') if policy(exercise).statistics? td.p-1 .btn-group button.btn.btn-outline-primary.btn-sm.dropdown-toggle data-bs-toggle='dropdown' type='button' = t('shared.actions_button') ul.dropdown-menu.float-end role='menu' - li = link_to(t('shared.show'), exercise, 'data-turbolinks': 'false', class: 'dropdown-item') if policy(exercise).show? + li = link_to(t('shared.show'), exercise, 'data-turbo': 'false', class: 'dropdown-item') if policy(exercise).show? li = link_to(UserExerciseFeedback.model_name.human(count: :other), feedback_exercise_path(exercise), class: 'dropdown-item') if policy(exercise).feedback? li = link_to(RequestForComment.model_name.human(count: :other), exercise_request_for_comments_path(exercise), class: 'dropdown-item') if policy(exercise).rfcs_for_exercise? li = link_to(ProgrammingGroup.model_name.human(count: :other), exercise_programming_groups_path(exercise), class: 'dropdown-item') if policy(exercise).programming_groups_for_exercise? diff --git a/app/views/exercises/show.html.slim b/app/views/exercises/show.html.slim index 0650457c2..31e0e9f6f 100644 --- a/app/views/exercises/show.html.slim +++ b/app/views/exercises/show.html.slim @@ -1,7 +1,7 @@ - content_for :head do // Force a full page reload, see https://github.com/turbolinks/turbolinks/issues/326. Otherwise, code might not be highlighted correctly (race condition) - meta name='turbolinks-visit-control' content='reload' + meta name='turbo-visit-control' content='reload' - append_javascript_pack_tag('highlight') - append_stylesheet_pack_tag('highlight') @@ -15,8 +15,8 @@ h1.d-inline-block = render('shared/edit_button', object: @exercise) button.btn.btn-secondary.float-end.dropdown-toggle data-bs-toggle='dropdown' type='button' ul.dropdown-menu.dropdown-menu-end role='menu' - li = link_to(t('exercises.index.implement'), implement_exercise_path(@exercise), 'data-turbolinks': 'false', class: 'dropdown-item') if policy(@exercise).implement? - li = link_to(t('shared.statistics'), statistics_exercise_path(@exercise), 'data-turbolinks': 'false', class: 'dropdown-item') if policy(@exercise).statistics? + li = link_to(t('exercises.index.implement'), implement_exercise_path(@exercise), 'data-turbo': 'false', class: 'dropdown-item') if policy(@exercise).implement? + li = link_to(t('shared.statistics'), statistics_exercise_path(@exercise), 'data-turbo': 'false', class: 'dropdown-item') if policy(@exercise).statistics? li = link_to(UserExerciseFeedback.model_name.human(count: :other), feedback_exercise_path(@exercise), class: 'dropdown-item') if policy(@exercise).feedback? li = link_to(RequestForComment.model_name.human(count: :other), exercise_request_for_comments_path(@exercise), class: 'dropdown-item') if policy(@exercise).rfcs_for_exercise? li = link_to(ProgrammingGroup.model_name.human(count: :other), exercise_programming_groups_path(@exercise), class: 'dropdown-item') if policy(@exercise).programming_groups_for_exercise? diff --git a/app/views/exercises/statistics.html.slim b/app/views/exercises/statistics.html.slim index ac4d50847..44449903e 100644 --- a/app/views/exercises/statistics.html.slim +++ b/app/views/exercises/statistics.html.slim @@ -1,7 +1,7 @@ - content_for :head do // Force a full page reload, see https://github.com/turbolinks/turbolinks/issues/326. Otherwise, code might not be highlighted correctly (race condition) - meta name='turbolinks-visit-control' content='reload' + meta name='turbo-visit-control' content='reload' - append_javascript_pack_tag('d3-tip') h1 = @exercise diff --git a/app/views/exercises/study_group_dashboard.html.slim b/app/views/exercises/study_group_dashboard.html.slim index d41a79486..d71ee6a9c 100644 --- a/app/views/exercises/study_group_dashboard.html.slim +++ b/app/views/exercises/study_group_dashboard.html.slim @@ -1,7 +1,7 @@ - content_for :head do // Force a full page reload, see https://github.com/turbolinks/turbolinks/issues/326. Otherwise, code might not be highlighted correctly (race condition) - meta name='turbolinks-visit-control' content='reload' + meta name='turbo-visit-control' content='reload' - append_javascript_pack_tag('d3-tip') h1 diff --git a/app/views/layouts/application.html.slim b/app/views/layouts/application.html.slim index 94e33a523..a3aa52b79 100644 --- a/app/views/layouts/application.html.slim +++ b/app/views/layouts/application.html.slim @@ -12,10 +12,10 @@ html lang=I18n.locale data-default-locale=I18n.default_locale = favicon_link_tag('/icon.png', rel: 'apple-touch-icon', type: 'image/png') = tag.link rel: 'manifest', href: pwa_manifest_path = action_cable_meta_tag - = stylesheet_pack_tag('application', 'stylesheets', media: 'all', 'data-turbolinks-track': 'reload', integrity: true, crossorigin: 'anonymous') - = stylesheet_link_tag('application', media: 'all', 'data-turbolinks-track': 'reload', integrity: true, crossorigin: 'anonymous') - = javascript_pack_tag('application', 'data-turbolinks-track': 'reload', defer: false, integrity: true, crossorigin: 'anonymous') - = javascript_include_tag('application', 'data-turbolinks-track': 'reload', integrity: true, crossorigin: 'anonymous') + = stylesheet_pack_tag('application', 'stylesheets', media: 'all', 'data-turbo-track': 'reload', integrity: true, crossorigin: 'anonymous') + = stylesheet_link_tag('application', media: 'all', 'data-turbo-track': 'reload', integrity: true, crossorigin: 'anonymous') + = javascript_pack_tag('application', 'data-turbo-track': 'reload', defer: false, integrity: true, crossorigin: 'anonymous') + = javascript_include_tag('application', 'data-turbo-track': 'reload', integrity: true, crossorigin: 'anonymous') = yield(:head) = csrf_meta_tags /= csp_meta_tag diff --git a/app/views/programming_groups/index.html.slim b/app/views/programming_groups/index.html.slim index 4b5dabde1..7a0ca76f7 100644 --- a/app/views/programming_groups/index.html.slim +++ b/app/views/programming_groups/index.html.slim @@ -30,7 +30,7 @@ tr td = link_to_if(policy(programming_group).show?, programming_group.displayname, programming_group) - if @exercise.nil? - td = link_to_if(policy(programming_group.exercise).show?, programming_group.exercise.title, programming_group.exercise, 'data-turbolinks': 'false') + td = link_to_if(policy(programming_group.exercise).show?, programming_group.exercise.title, programming_group.exercise, 'data-turbo': 'false') td == programming_group.users.map {|user| link_to_if(policy(user).show?, user.name, user) }.join(', ') td = programming_group.users.size td = l(programming_group.created_at, format: :short) diff --git a/app/views/proxy_exercises/_form.html.slim b/app/views/proxy_exercises/_form.html.slim index 472bcb8f6..7a639e6a6 100644 --- a/app/views/proxy_exercises/_form.html.slim +++ b/app/views/proxy_exercises/_form.html.slim @@ -1,7 +1,7 @@ - content_for :head do // Force a full page reload, see https://github.com/turbolinks/turbolinks/issues/326. Otherwise, code might not be highlighted correctly (race condition) - meta name='turbolinks-visit-control' content='reload' + meta name='turbo-visit-control' content='reload' - append_javascript_pack_tag('toast-ui') - append_stylesheet_pack_tag('toast-ui') diff --git a/app/views/proxy_exercises/index.html.slim b/app/views/proxy_exercises/index.html.slim index e596262cf..9d317daa8 100644 --- a/app/views/proxy_exercises/index.html.slim +++ b/app/views/proxy_exercises/index.html.slim @@ -31,7 +31,7 @@ h1 = ProxyExercise.model_name.human(count: :other) span.caret span.visually-hidden Toggle Dropdown ul.dropdown-menu.float-end role='menu' - li = link_to(t('shared.show'), proxy_exercise, 'data-turbolinks': 'false', class: 'dropdown-item') if policy(proxy_exercise).show? + li = link_to(t('shared.show'), proxy_exercise, 'data-turbo': 'false', class: 'dropdown-item') if policy(proxy_exercise).show? li = link_to(t('shared.destroy'), proxy_exercise, data: {confirm: t('shared.confirm_destroy')}, method: :delete, class: 'dropdown-item') if policy(proxy_exercise).destroy? li = link_to(t('.clone'), clone_proxy_exercise_path(proxy_exercise), data: {confirm: t('shared.confirm_destroy')}, method: :post, class: 'dropdown-item') if policy(proxy_exercise).clone? diff --git a/app/views/statistics/activity_history.html.slim b/app/views/statistics/activity_history.html.slim index 631a9d38c..93d5e1e0c 100644 --- a/app/views/statistics/activity_history.html.slim +++ b/app/views/statistics/activity_history.html.slim @@ -1,7 +1,7 @@ - content_for :head do // Force a full page reload, see https://github.com/turbolinks/turbolinks/issues/326. Otherwise, the global variable `vis` might be uninitialized in the assets (race condition) - meta name='turbolinks-visit-control' content='reload' + meta name='turbo-visit-control' content='reload' - append_javascript_pack_tag('vis') - append_stylesheet_pack_tag('vis') diff --git a/app/views/statistics/graphs.html.slim b/app/views/statistics/graphs.html.slim index dbefd5ad0..7796d3719 100644 --- a/app/views/statistics/graphs.html.slim +++ b/app/views/statistics/graphs.html.slim @@ -1,7 +1,7 @@ - content_for :head do // Force a full page reload, see https://github.com/turbolinks/turbolinks/issues/326. Otherwise, the global variable `vis` might be uninitialized in the assets (race condition) - meta name='turbolinks-visit-control' content='reload' + meta name='turbo-visit-control' content='reload' - append_javascript_pack_tag('vis') - append_stylesheet_pack_tag('vis') diff --git a/app/views/submissions/show.html.slim b/app/views/submissions/show.html.slim index 2bd983e0b..7441e2ea5 100644 --- a/app/views/submissions/show.html.slim +++ b/app/views/submissions/show.html.slim @@ -1,7 +1,7 @@ - content_for :head do // Force a full page reload, see https://github.com/turbolinks/turbolinks/issues/326. Otherwise, code might not be highlighted correctly (race condition) - meta name='turbolinks-visit-control' content='reload' + meta name='turbo-visit-control' content='reload' - append_javascript_pack_tag('highlight') - append_stylesheet_pack_tag('highlight') diff --git a/app/views/tips/_form.html.slim b/app/views/tips/_form.html.slim index c8c4b746a..139b12e1d 100644 --- a/app/views/tips/_form.html.slim +++ b/app/views/tips/_form.html.slim @@ -1,7 +1,7 @@ - content_for :head do // Force a full page reload, see https://github.com/turbolinks/turbolinks/issues/326. Otherwise, code might not be highlighted correctly (race condition) - meta name='turbolinks-visit-control' content='reload' + meta name='turbo-visit-control' content='reload' - append_javascript_pack_tag('toast-ui') - append_stylesheet_pack_tag('toast-ui') diff --git a/app/views/tips/show.html.slim b/app/views/tips/show.html.slim index 4d09f29a8..1c1ae463b 100644 --- a/app/views/tips/show.html.slim +++ b/app/views/tips/show.html.slim @@ -1,7 +1,7 @@ - content_for :head do // Force a full page reload, see https://github.com/turbolinks/turbolinks/issues/326. Otherwise, code might not be highlighted correctly (race condition) - meta name='turbolinks-visit-control' content='reload' + meta name='turbo-visit-control' content='reload' - append_javascript_pack_tag('highlight') - append_stylesheet_pack_tag('highlight') diff --git a/app/views/webauthn_credential_authentication/new.html.slim b/app/views/webauthn_credential_authentication/new.html.slim index df206b7b0..76e51de57 100644 --- a/app/views/webauthn_credential_authentication/new.html.slim +++ b/app/views/webauthn_credential_authentication/new.html.slim @@ -1,7 +1,7 @@ - content_for :head do // Force a full page reload, see https://github.com/turbolinks/turbolinks/issues/326. Otherwise, the global variable `vis` might be uninitialized in the assets (race condition) - meta name='turbolinks-visit-control' content='reload' + meta name='turbo-visit-control' content='reload' - append_javascript_pack_tag('webauthn') h1 = t('.headline') diff --git a/app/views/webauthn_credentials/new.html.slim b/app/views/webauthn_credentials/new.html.slim index 5bbfb5f03..8c8f8e76c 100644 --- a/app/views/webauthn_credentials/new.html.slim +++ b/app/views/webauthn_credentials/new.html.slim @@ -1,7 +1,7 @@ - content_for :head do // Force a full page reload, see https://github.com/turbolinks/turbolinks/issues/326. Otherwise, the global variable `vis` might be uninitialized in the assets (race condition) - meta name='turbolinks-visit-control' content='reload' + meta name='turbo-visit-control' content='reload' - append_javascript_pack_tag('webauthn') h1 = t('shared.new_model', model: WebauthnCredential.model_name.human) diff --git a/config/locales/de/programming_group.yml b/config/locales/de/programming_group.yml index 2908e0599..d55deae2a 100644 --- a/config/locales/de/programming_group.yml +++ b/config/locales/de/programming_group.yml @@ -35,5 +35,5 @@ de: own_user_id: 'Ihre Personen-ID:' pair_programming_info: Pair Programming Info work_alone: Alleine arbeiten - work_alone_description: Sie können sich einmalig dafür entscheiden, die Aufgabe alleine zu bearbeiten. Anschließend können Sie jedoch nicht mehr in die Partnerarbeit für diese Aufgabe wechseln.
Klicken Sie hier, um die Aufgabe im Einzelmodus zu starten. + work_alone_description: Sie können sich einmalig dafür entscheiden, die Aufgabe alleine zu bearbeiten. Anschließend können Sie jedoch nicht mehr in die Partnerarbeit für diese Aufgabe wechseln.
Klicken Sie hier, um die Aufgabe im Einzelmodus zu starten. work_with_a_friend: Mit einem/einer Freund:in zusammenarbeiten diff --git a/config/locales/en/programming_group.yml b/config/locales/en/programming_group.yml index e96be6b40..8db57d807 100644 --- a/config/locales/en/programming_group.yml +++ b/config/locales/en/programming_group.yml @@ -35,5 +35,5 @@ en: own_user_id: 'Your user ID:' pair_programming_info: Pair Programming Info work_alone: Work Alone - work_alone_description: You can choose once to work on the exercise alone. Afterward, however, you will not be able to switch to work in a pair for this exercise.
Click here to get to the exercise in single mode. + work_alone_description: You can choose once to work on the exercise alone. Afterward, however, you will not be able to switch to work in a pair for this exercise.
Click here to get to the exercise in single mode. work_with_a_friend: Work with a friend diff --git a/lib/assets/javascripts/color_mode_picker.js b/lib/assets/javascripts/color_mode_picker.js index b3ce96cef..3fe259279 100644 --- a/lib/assets/javascripts/color_mode_picker.js +++ b/lib/assets/javascripts/color_mode_picker.js @@ -77,7 +77,7 @@ function showActiveTheme(theme, focus = false) { } } -$(document).on('turbolinks:load', function() { +$(document).on('turbo:load', function() { setTheme(getPreferredTheme()) window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { diff --git a/lib/assets/javascripts/flash.js b/lib/assets/javascripts/flash.js index f1bfa6100..a86f2b8d1 100644 --- a/lib/assets/javascripts/flash.js +++ b/lib/assets/javascripts/flash.js @@ -1,4 +1,4 @@ -$( document ).on('turbolinks:load', function() { +$( document ).on('turbo:load', function() { var DURATION = 10000; var SEVERITIES = ['danger', 'info', 'success', 'warning']; diff --git a/package.json b/package.json index 0cd3eb223..476255f90 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "@egjs/hammerjs": "^2.0.17", "@fortawesome/fontawesome-free": "^6.7.2", "@github/webauthn-json": "^2.1.1", + "@hotwired/turbo-rails": "^8.0.16", "@popperjs/core": "^2.11.8", "@sentry/browser": "^9.27.0", "@toast-ui/editor": "^3.2.2", diff --git a/spec/support/wait_for_ajax.rb b/spec/support/wait_for_ajax.rb index 9baf7bcff..42d4e139c 100644 --- a/spec/support/wait_for_ajax.rb +++ b/spec/support/wait_for_ajax.rb @@ -2,6 +2,8 @@ module WaitForAjax def wait_for_ajax + wait_for_turbojs + start_time = Time.current timeout = Capybara.default_max_wait_time @@ -11,6 +13,11 @@ def wait_for_ajax end end + def wait_for_turbojs + has_css?('.turbo-progress-bar', visible: true) + has_no_css?('.turbo-progress-bar') + end + def ajax_requests_finished? # This method MUST NOT be interrupted. Hence, Timeout.timeout is not used here. # Otherwise, Selenium and the browser driver might crash, preventing further tests from running. diff --git a/yarn.lock b/yarn.lock index 4e724a925..ff705da0f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1251,6 +1251,16 @@ __metadata: languageName: node linkType: hard +"@hotwired/turbo-rails@npm:^8.0.16": + version: 8.0.16 + resolution: "@hotwired/turbo-rails@npm:8.0.16" + dependencies: + "@hotwired/turbo": "npm:^8.0.13" + "@rails/actioncable": "npm:>=7.0" + checksum: 10c0/a3781bf5e7c798307754a726b5b66f63e4ec71a74e508549f257b3acf834ffc5c28baaf03b8dcdeeb7b35caa361769e417bbca629dcf873729398773585d35ca + languageName: node + linkType: hard + "@hotwired/turbo@npm:^7.3.0": version: 7.3.0 resolution: "@hotwired/turbo@npm:7.3.0" @@ -1258,6 +1268,13 @@ __metadata: languageName: node linkType: hard +"@hotwired/turbo@npm:^8.0.13": + version: 8.0.13 + resolution: "@hotwired/turbo@npm:8.0.13" + checksum: 10c0/fc9fd58ce2e006ad2f9e3948cf1ec71f47187ce8115f03e531bab849d0e13abc94cd0067f0888f7064d730b4c1a8212101bfa6d55f6166c6ad2db275e280149a + languageName: node + linkType: hard + "@isaacs/cliui@npm:^8.0.2": version: 8.0.2 resolution: "@isaacs/cliui@npm:8.0.2" @@ -1575,6 +1592,13 @@ __metadata: languageName: node linkType: hard +"@rails/actioncable@npm:>=7.0": + version: 8.0.200 + resolution: "@rails/actioncable@npm:8.0.200" + checksum: 10c0/42c861f3b43131ab523d37125e30e802bd5bab98bf8150a780531f82f05177cd0071a75a7f1341eac9de772732625194ac16205a40b82dc567cc05c21c56e412 + languageName: node + linkType: hard + "@rails/actioncable@npm:^7.0": version: 7.2.201 resolution: "@rails/actioncable@npm:7.2.201" @@ -2658,6 +2682,7 @@ __metadata: "@egjs/hammerjs": "npm:^2.0.17" "@fortawesome/fontawesome-free": "npm:^6.7.2" "@github/webauthn-json": "npm:^2.1.1" + "@hotwired/turbo-rails": "npm:^8.0.16" "@popperjs/core": "npm:^2.11.8" "@sentry/browser": "npm:^9.27.0" "@toast-ui/editor": "npm:^3.2.2" From 0d0e50caa9f84ffd9c00b23325af445d48719e12 Mon Sep 17 00:00:00 2001 From: Armin Kirchner Date: Fri, 13 Jun 2025 10:50:14 +0200 Subject: [PATCH 2/3] move to map --- app/javascript/tooltip.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/tooltip.js b/app/javascript/tooltip.js index d56cea401..9304acba7 100644 --- a/app/javascript/tooltip.js +++ b/app/javascript/tooltip.js @@ -1,4 +1,4 @@ -const tooltipMap = new WeakMap(); +const tooltipMap = new Map(); function manageTooltips() { const selector = '[data-bs-toggle="tooltip"]'; From 5a19ab7486b14e32058e8da36edb956cc06bc578 Mon Sep 17 00:00:00 2001 From: Armin Kirchner Date: Fri, 13 Jun 2025 12:21:31 +0200 Subject: [PATCH 3/3] Disable turbo on all form submissions --- app/views/exercises/_editor_output.html.slim | 2 +- app/views/exercises/_export_actions.html.slim | 2 +- app/views/internal_users/activate.html.slim | 2 +- app/views/internal_users/change_password.html.slim | 2 +- app/views/internal_users/forgot_password.html.slim | 2 +- app/views/internal_users/reset_password.html.slim | 2 +- app/views/sessions/new.html.slim | 2 +- app/views/shared/_form_filters.html.slim | 2 +- app/views/shared/_submit_button.html.slim | 2 +- app/views/statistics/activity_history.html.slim | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/views/exercises/_editor_output.html.slim b/app/views/exercises/_editor_output.html.slim index 99566273d..a0bc887be 100644 --- a/app/views/exercises/_editor_output.html.slim +++ b/app/views/exercises/_editor_output.html.slim @@ -73,7 +73,7 @@ span.input-group-text data-prompt=t('exercises.editor.input') = t('exercises.editor.input') input#prompt-input.form-control type='text' span.input-group-btn - button#prompt-submit.btn.btn-primary type='button' = t('exercises.editor.send') + button#prompt-submit.btn.btn-primary type='button' data-turbo='false' = t('exercises.editor.send') - unless @embed_options[:disable_hints] #error-hints.mb-2.p-2 .heading = t('exercises.implement.error_hints.heading') diff --git a/app/views/exercises/_export_actions.html.slim b/app/views/exercises/_export_actions.html.slim index 5849688ab..23c48ba84 100644 --- a/app/views/exercises/_export_actions.html.slim +++ b/app/views/exercises/_export_actions.html.slim @@ -7,6 +7,6 @@ i.fa-solid.fa-check.confirm-icon = t('exercises.export_codeharbor.buttons.export') -= button_tag type: 'submit', class: 'btn btn-secondary float-end export-button', data: {bs_dismiss: 'modal'} do += button_tag type: 'submit', class: 'btn btn-secondary float-end export-button', data: {bs_dismiss: 'modal', turbo: 'false'} do i.fa-solid.fa-xmark.abort-icon = exported ? t('shared.close') : t('exercises.export_codeharbor.buttons.abort') diff --git a/app/views/internal_users/activate.html.slim b/app/views/internal_users/activate.html.slim index 6db954fc4..5224f79d8 100644 --- a/app/views/internal_users/activate.html.slim +++ b/app/views/internal_users/activate.html.slim @@ -9,4 +9,4 @@ h1 = t('.headline') = f.label(:password_confirmation, class: 'form-label') = f.password_field(:password_confirmation, class: 'form-control', required: true, autocomplete: 'new-password') = f.hidden_field(:activation_token) - .actions = submit_tag(t('.submit'), class: 'btn btn-primary') + .actions = submit_tag(t('.submit'), class: 'btn btn-primary', data: {turbo: false}) diff --git a/app/views/internal_users/change_password.html.slim b/app/views/internal_users/change_password.html.slim index 864f7cc0d..59661f81f 100644 --- a/app/views/internal_users/change_password.html.slim +++ b/app/views/internal_users/change_password.html.slim @@ -13,4 +13,4 @@ h1 = t('.headline') = f.label(:current_password, class: 'form-label') = f.password_field(:current_password, class: 'form-control', required: true, autocomplete: 'current-password') .help-block.form-text = t('.hints.current_password') - .actions = submit_tag(t('.submit'), class: 'btn btn-primary') + .actions = submit_tag(t('.submit'), class: 'btn btn-primary', data: {turbo: false}) diff --git a/app/views/internal_users/forgot_password.html.slim b/app/views/internal_users/forgot_password.html.slim index 748573105..2799c0aca 100644 --- a/app/views/internal_users/forgot_password.html.slim +++ b/app/views/internal_users/forgot_password.html.slim @@ -4,4 +4,4 @@ h1 = t('.headline') .mb-3 = label_tag(:email, InternalUser.human_attribute_name('email')) = email_field_tag(:email, params[:email], autofocus: true, class: 'form-control', required: true, autocomplete: 'email') - .actions = submit_tag(t('.submit'), class: 'btn btn-primary') + .actions = submit_tag(t('.submit'), class: 'btn btn-primary', data: {trubo: false}) diff --git a/app/views/internal_users/reset_password.html.slim b/app/views/internal_users/reset_password.html.slim index ed007502a..3af3cc07d 100644 --- a/app/views/internal_users/reset_password.html.slim +++ b/app/views/internal_users/reset_password.html.slim @@ -9,4 +9,4 @@ h1 = t('.headline') = f.label(:password_confirmation, class: 'form-label') = f.password_field(:password_confirmation, class: 'form-control', required: true, autocomplete: 'new-password') = f.hidden_field(:reset_password_token) - .actions = submit_tag(t('.submit'), class: 'btn btn-primary') + .actions = submit_tag(t('.submit'), class: 'btn btn-primary', data: {trubo: false}) diff --git a/app/views/sessions/new.html.slim b/app/views/sessions/new.html.slim index c1e709d6d..6d3f6c9c2 100644 --- a/app/views/sessions/new.html.slim +++ b/app/views/sessions/new.html.slim @@ -21,4 +21,4 @@ h1 = t('.headline') = check_box_tag(:remember_me, 1, true, class: 'form-check-input') = t('.remember_me') span.float-end = link_to(t('.forgot_password'), forgot_password_path) - .actions = submit_tag(t('.link'), class: 'btn btn-primary') + .actions = submit_tag(t('.link'), class: 'btn btn-primary', data: {turbo: false}) diff --git a/app/views/shared/_form_filters.html.slim b/app/views/shared/_form_filters.html.slim index d47162fd3..066a312bd 100644 --- a/app/views/shared/_form_filters.html.slim +++ b/app/views/shared/_form_filters.html.slim @@ -3,7 +3,7 @@ = yield(f) .col-sm.ge-4.gy-2 .btn-group.float-end.ms-auto.text-nowrap - button.btn.btn-primary type='submit' = t('shared.apply_filters') + button.btn.btn-primary type='submit' data-turbo='false' = t('shared.apply_filters') button.btn.btn-primary.dropdown-toggle data-bs-toggle='dropdown' type='button' ul.dropdown-menu.dropdown-menu-end role='menu' li diff --git a/app/views/shared/_submit_button.html.slim b/app/views/shared/_submit_button.html.slim index 7657d97d8..1bf61d41f 100644 --- a/app/views/shared/_submit_button.html.slim +++ b/app/views/shared/_submit_button.html.slim @@ -1 +1 @@ -= f.submit(class: 'btn btn-primary', value: t(object.new_record? ? 'shared.create' : 'shared.update', model: object.class.model_name.human)) += f.submit(class: 'btn btn-primary', value: t(object.new_record? ? 'shared.create' : 'shared.update', model: object.class.model_name.human), data: {turbo: false}) diff --git a/app/views/statistics/activity_history.html.slim b/app/views/statistics/activity_history.html.slim index 93d5e1e0c..85e8eaa65 100644 --- a/app/views/statistics/activity_history.html.slim +++ b/app/views/statistics/activity_history.html.slim @@ -24,4 +24,4 @@ select.form-control#interval name='interval' = %i[year quarter month day hour minute second].each do |key| option selected=(key.to_s == params[:interval]) = key - button.btn.btn-primary type='submit' = t('.update') + button.btn.btn-primary type='submit' data-turbo='false' = t('.update')