Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ jobs:
env:
RAILS_ENV: test
CC_TEST_REPORTER_ID: true
# Use Firefox for system tests until Chrome headless works reliably again.
# See https://github.com/SeleniumHQ/selenium/issues/15273
BROWSER: firefox
run: bundle exec rspec --color --format RSpec::Github::Formatter --format progress

- name: Upload coverage reports to Codecov
Expand Down
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand Down
7 changes: 1 addition & 6 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -618,9 +618,6 @@ GEM
turbo-rails (2.0.16)
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)
Expand Down Expand Up @@ -750,7 +747,7 @@ DEPENDENCIES
telegraf
terser
tubesock!
turbolinks
turbo-rails
web-console
webauthn
webmock
Expand Down Expand Up @@ -993,8 +990,6 @@ CHECKSUMS
tpm-key_attestation (0.14.1) sha256=7fd4e4653a7afd0a386632ddfb05d10ecfdd47678299c5e69165bc9ae111193f
tubesock (0.2.9)
turbo-rails (2.0.16) sha256=d24e1b60f0c575b3549ecda967e5391027143f8220d837ed792c8d48ea0ea38d
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
Expand Down
6 changes: 5 additions & 1 deletion app/assets/javascripts/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
//
Expand All @@ -35,3 +34,8 @@
//
// All remaining assets are loaded in alphabetical order
//= require_tree .
//
// Finally, we dispatch a custom event to signal that all assets are loaded.
// This is used by our custom migration for Turbo to trigger the `turbo-migration:load` event
const sprocketsLoad = new Event('sprockets:load');
document.dispatchEvent(sprocketsLoad);
11 changes: 4 additions & 7 deletions app/assets/javascripts/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Array.prototype.includes = function(element) {

window.CodeOcean = {
refresh: function() {
Turbolinks.visit(window.location.pathname);
Turbo.visit(window.location.pathname);
}
};

Expand All @@ -24,7 +24,7 @@ $.fn.scrollTo = function(selector) {
}, ANIMATION_DURATION);
};

$(document).on('turbolinks:load', function() {
$(document).on('turbo-migration: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();
Expand All @@ -45,7 +45,7 @@ $(document).on('turbolinks:load', function() {
// Initialize Sentry
const sentrySettings = $('meta[name="sentry"]')

// Workaround for Turbolinks: We must not re-initialize the Relay object when visiting another page
// Workaround for Turbo: We must not re-initialize the Relay object when visiting another page
if (sentrySettings && sentrySettings.data()['enabled'] && Sentry.getReplay() === undefined) {
Sentry.init({
dsn: sentrySettings.data('dsn'),
Expand All @@ -66,10 +66,7 @@ $(document).on('turbolinks:load', function() {
});
}

// Enable all tooltips
$('[data-bs-toggle="tooltip"]').tooltip();

// Enable sorttable again, as it is disabled otherwise by Turbolinks
// Enable sorttable again, as it is disabled otherwise by Turbo
if (sorttable) {
sorttable.init.done = false;
sorttable.init();
Expand Down
2 changes: 1 addition & 1 deletion app/assets/javascripts/bootstrap-dropdown-submenu.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
$(document).on('turbolinks:load', function() {
$(document).on('turbo-migration:load', function() {

var subMenusSelector = 'ul.dropdown-menu [data-bs-toggle=dropdown]';

Expand Down
4 changes: 2 additions & 2 deletions app/assets/javascripts/channels/la_exercises.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
$(document).on('turbolinks:load', function() {
$(document).on('turbo-migration:load', function() {
if ($.isController('exercises') && $('.teacher_dashboard').isPresent()) {

const exercise_id = $('.teacher_dashboard').data().exerciseId;
Expand All @@ -11,7 +11,7 @@ $(document).on('turbolinks:load', function() {

function addClickEventToRfCEntry($row) {
$row.click(function () {
Turbolinks.visit($(this).data("href"));
Turbo.visit($(this).data("href"));
});
}

Expand Down
2 changes: 1 addition & 1 deletion app/assets/javascripts/channels/pg_matching_channel.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
$(document).on('turbolinks:load', function () {
$(document).on('turbo-migration:load', function () {

if ($.isController('programming_groups') && window.location.pathname.includes('programming_groups/new')) {
const matching_page = $('#matching');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
$(document).on('turbolinks:load', function () {
$(document).on('turbo-migration:load', function () {

if (window.location.pathname.includes('/implement')) {
var editor = $('#editor');
Expand Down
3 changes: 1 addition & 2 deletions app/assets/javascripts/codeharbor_link.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
$(document).on('turbolinks:load', function() {
$(document).on('turbo-migration:load', function() {
if($.isController('codeharbor_links')) {
if ($('.edit_codeharbor_link, .new_codeharbor_link').isPresent()) {

Expand Down Expand Up @@ -33,4 +33,3 @@ $(document).on('turbolinks:load', function() {
}
}
});

21 changes: 15 additions & 6 deletions app/assets/javascripts/community_solution.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
$(document).on('turbolinks:load', function() {
$(document).on('turbo-migration:load', function() {

if ($.isController('community_solutions') && $('#community-solution-editor').isPresent()) {
CodeOceanEditor.sendEvents = false;
Expand All @@ -25,6 +25,18 @@ $(document).on('turbolinks:load', function() {
}
});

$(document).one('turbo-migration:load', function() {
if ($.isController('community_solutions') && $('#community-solution-editor').isPresent()) {
$(document).one('turbo:visit', unloadEditorHandler);
$(window).one('beforeunload', unloadEditorHandler);
}
});

function unloadEditorHandler() {
CodeOceanEditor.autosaveIfChanged();
CodeOceanEditor.unloadEditor();
}

function submitCode(event) {
const button = $(event.target) || $('#submit');
this.newSentryTransaction(button, async () => {
Expand All @@ -35,10 +47,7 @@ function submitCode(event) {
if (!submission) return;
if (!submission.redirect) return;

this.autosaveIfChanged();
await this.stopCode(event);
this.editors = [];
Turbolinks.clearCache();
Turbolinks.visit(submission.redirect);
unloadEditorHandler();
Turbo.visit(submission.redirect);
});
}
2 changes: 1 addition & 1 deletion app/assets/javascripts/dashboard.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
$(document).on('turbolinks:load', function() {
$(document).on('turbo-migration:load', function() {
var CHART_START = window.vis ? vis.moment().add(-1, 'minute') : undefined;
var DEFAULT_REFRESH_INTERVAL = 5000;

Expand Down
18 changes: 9 additions & 9 deletions app/assets/javascripts/editor.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
$(document).on('turbolinks:load', function(event) {
$(document).on('turbo-migration:load', function(event) {

//Merge all editor components.
$.extend(
Expand All @@ -13,16 +13,16 @@ $(document).on('turbolinks:load', function(event) {
CodeOceanEditorRequestForComments
);

if ($('#editor').isPresent() && CodeOceanEditor && event.originalEvent.data.url.includes("/implement")) {
if ($('#editor').isPresent() && CodeOceanEditor && event.detail.url.includes("/implement")) {
CodeOceanEditor.initializeEverything();
}
});

function handleThemeChangeEvent(event) {
if (CodeOceanEditor) {
CodeOceanEditor.THEME = event.detail.currentTheme === 'dark' ? 'ace/theme/tomorrow_night' : 'ace/theme/tomorrow';
document.dispatchEvent(new Event('theme:change:ace'));
}
function handleThemeChangeEvent(event) {
if (CodeOceanEditor) {
CodeOceanEditor.THEME = event.detail.currentTheme === 'dark' ? 'ace/theme/tomorrow_night' : 'ace/theme/tomorrow';
document.dispatchEvent(new Event('theme:change:ace'));
}
}

$(document).on('theme:change', handleThemeChangeEvent.bind(this));
});
$(document).on('theme:change', handleThemeChangeEvent);
71 changes: 58 additions & 13 deletions app/assets/javascripts/editor/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,8 @@ var CodeOceanEditor = {
}

const bottom = considerStatusbar ? ($('#statusbar').height() || 0) : 0;
// calculate needed size: window height - position of top of ACE editor - height of autosave label below editor - 5 for bar margins
return window.innerHeight - jqueryElement.offset().top - bottom - 5;
// calculate needed size: window height - position of top of ACE editor - height of autosave label below editor - 7 for bar margins
return window.innerHeight - jqueryElement.offset().top - bottom - 7;
},

resizeParentOfAceEditor: function (element) {
Expand Down Expand Up @@ -418,15 +418,39 @@ var CodeOceanEditor = {
this.showFrame(frame);
this.toggleButtonStates();
}.bind(this));
$(document).on('theme:change', function(event) {

this.installFileTreeEventHandlers(filesInstance);
},

installFileTreeEventHandlers: function (filesInstance) {
// Prevent duplicate event listeners by removing them during unload.
const themeListener = this.createFileTreeThemeChangeListener(filesInstance);
const jsTree = filesInstance?.jstree(true);
$(document).on('theme:change', themeListener);
$(document).one('turbo:visit', function() {
$(document).off('theme:change', themeListener);
if (jsTree && jsTree.element) {
jsTree.destroy(true);
}
});
$(window).one('beforeunload', function() {
$(document).off('theme:change', themeListener);
if (jsTree && jsTree.element) {
jsTree.destroy(true);
}
});
},

createFileTreeThemeChangeListener: function (filesInstance) {
return function (event) {
const jsTree = filesInstance?.jstree(true);

if (jsTree) {
const newColorScheme = event.detail.currentTheme;
// Update the JStree theme
jsTree?.set_theme(newColorScheme === "dark" ? "default-dark" : "default");
}
});
}
},

initializeFileTreeButtons: function () {
Expand Down Expand Up @@ -935,10 +959,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));
Expand Down Expand Up @@ -1096,7 +1116,6 @@ var CodeOceanEditor = {
this.initializeSideBarCollapse();
this.initializeOutputBarToggle();
this.initializeDescriptionToggle();
this.initializeSideBarTooltips();
this.initializeInterventionTimer();
this.initPrompt();
this.renderScore();
Expand All @@ -1106,12 +1125,38 @@ var CodeOceanEditor = {
this.initializeDeadlines();
CodeOceanEditorTips.initializeEventHandlers();

window.addEventListener("turbolinks:before-render", App.synchronized_editor?.disconnect.bind(App.synchronized_editor));
window.addEventListener("beforeunload", App.synchronized_editor?.disconnect.bind(App.synchronized_editor));
$(document).one("turbo:visit", this.unloadEverything.bind(this, App.synchronized_editor));
$(window).one("beforeunload", this.unloadEverything.bind(this, App.synchronized_editor));

window.addEventListener("turbolinks: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();
},

unloadEverything: function () {
App.synchronized_editor?.disconnect();
this.autosaveIfChanged();
this.unloadEditor();
this.teardownEventHandlers();
},

unloadEditor: function () {
$(document).off('theme:change:ace');
CodeOceanEditor.cacheEditorContent();
CodeOceanEditor.destroyEditors();
},

cacheEditorContent: function () {
// Persist the content of the editors in a hidden textarea to enable Turbo caching.
// In this case, we iterate over _all_ editors, not just writable ones.
for (const [file_id, editor] of this.editor_for_file) {
const file_content = editor.getValue();
const editorContent = $(`.editor-content[data-file-id='${file_id}']`);
editorContent.text(file_content);
}
},

destroyEditors: function () {
CodeOceanEditor.editors.forEach(editor => editor.destroy());
CodeOceanEditor.editors = [];
}
};
2 changes: 1 addition & 1 deletion app/assets/javascripts/error_templates.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
$(document).on('turbolinks:load', function() {
$(document).on('turbo-migration:load', function() {
if ($.isController('error_templates')) {
const button = $('#add-attribute').find('button')
button.on('click', function () {
Expand Down
4 changes: 2 additions & 2 deletions app/assets/javascripts/exercise_collections.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
$(document).on('turbolinks:load', function() {
$(document).on('turbo-migration:load', function() {
if ($.isController('exercise_collections')) {
var dataElement = $('#data');
var exerciseList = $('#exercise-list');
Expand Down Expand Up @@ -100,7 +100,7 @@ $(document).on('turbolinks:load', function() {
tooltip.style("display", "none");
})
.on("click", function (_event, d) {
Turbolinks.visit(Routes.statistics_exercise_path(d.exercise_id));
Turbo.visit(Routes.statistics_exercise_path(d.exercise_id));
})
.attr("x", function (d) {
return x(d.index);
Expand Down
2 changes: 1 addition & 1 deletion app/assets/javascripts/exercise_graphs.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
$(document).on('turbolinks:load', function() {
$(document).on('turbo-migration:load', function() {
// /exercises/38/statistics good for testing

if ($.isController('exercises') && $('.graph-functions-2').isPresent()) {
Expand Down
Loading