diff --git a/app/assets/javascripts/channels/synchronized_editor_channel.js b/app/assets/javascripts/channels/synchronized_editor_channel.js index 03648230..70168549 100644 --- a/app/assets/javascripts/channels/synchronized_editor_channel.js +++ b/app/assets/javascripts/channels/synchronized_editor_channel.js @@ -32,6 +32,7 @@ $(document).on('turbolinks:load', function () { disconnected() { // Called when the subscription has been terminated by the server + alert(I18n.t('programming_groups.implement.info_disconnected')); }, received(data) { @@ -43,6 +44,11 @@ $(document).on('turbolinks:load', function () { } break; case 'connection_change': + // TODO: Check session id instead of user id to support multiple windows per user + if (is_other_user(data.user) && data.status === 'connected') { + const message = {files: CodeOceanEditor.collectFiles(), session_id: session_id}; + this.perform('current_content', message); + } if (is_other_user(data.user)) { CodeOceanEditor.showPartnersConnectionStatus(data.status, data.user.displayname); this.perform('connection_status'); @@ -60,6 +66,11 @@ $(document).on('turbolinks:load', function () { CodeOceanEditor.showPartnersConnectionStatus(data.status, data.user.displayname); } break; + case 'current_content': + if (is_other_session(data.session_id)) { + CodeOceanEditor.setEditorContent(data); + } + break; } }, diff --git a/app/assets/javascripts/editor/editor.js.erb b/app/assets/javascripts/editor/editor.js.erb index 531ac11a..a019c6a6 100644 --- a/app/assets/javascripts/editor/editor.js.erb +++ b/app/assets/javascripts/editor/editor.js.erb @@ -311,7 +311,7 @@ var CodeOceanEditor = { editor.commands.bindKey("ctrl+alt+0", null); this.editors.push(editor); - this.editor_for_file.set($(element).parent().data('filename'), editor); + this.editor_for_file.set($(element).data('file-id'), editor); var session = editor.getSession(); var mode = $(element).data('mode') session.setMode(mode); @@ -753,7 +753,7 @@ var CodeOceanEditor = { this.setActiveFile(frame.data('filename'), file_id); this.selectFileInJsTree($('#files'), file_id); - const editor = this.editor_for_file.get(file); + const editor = this.editor_for_file.get(file_id); editor.gotoLine(line, 0); event.preventDefault(); }, @@ -1061,7 +1061,7 @@ var CodeOceanEditor = { }, applyChanges: function (delta, active_file) { - const editor = this.editor_for_file.get(active_file.filename) + const editor = this.editor_for_file.get(active_file.id) editor.session.doc.applyDeltas([delta]); }, diff --git a/app/assets/javascripts/editor/submissions.js b/app/assets/javascripts/editor/submissions.js index 1859c0b7..0ec459cd 100644 --- a/app/assets/javascripts/editor/submissions.js +++ b/app/assets/javascripts/editor/submissions.js @@ -119,15 +119,21 @@ CodeOceanEditorSubmissions = { url: $('#start-over').data('url') || $('#start-over-active-file').data('url') }).done(function(response) { this.hideSpinner(); - _.each(this.editors, function(editor) { - var file_id = $(editor.container).data('file-id'); - var file = _.find(response.files, function(file) { - return file.id === file_id; - }); - if(file && !onlyActiveFile || file && file.id === CodeOceanEditor.active_file.id){ - editor.setValue(file.content); - } - }.bind(this)); + this.setEditorContent(response, onlyActiveFile); + }.bind(this)); + }, + + setEditorContent: function(new_content, onlyActiveFile = false) { + _.each(this.editors, function(editor) { + const editor_file_id = $(editor.container).data('file-id'); + const found_file = _.find(new_content.files, function(file) { + // File.id is used to reload the exercise and file.file_id is used to update the editor content for pair programming group members + return (file.id || file.file_id) === editor_file_id; + }); + if(found_file && !onlyActiveFile || found_file && found_file.id === CodeOceanEditor.active_file.id){ + editor.setValue(found_file.content); + editor.clearSelection(); + } }.bind(this)); }, diff --git a/app/channels/synchronized_editor_channel.rb b/app/channels/synchronized_editor_channel.rb index 04c03d9c..cb3c12d7 100644 --- a/app/channels/synchronized_editor_channel.rb +++ b/app/channels/synchronized_editor_channel.rb @@ -38,6 +38,10 @@ class SynchronizedEditorChannel < ApplicationCable::Channel ActionCable.server.broadcast(specific_channel, create_message('connection_status', 'connected')) end + def current_content(message) + ActionCable.server.broadcast(specific_channel, message) + end + def create_message(action, status) { action:, diff --git a/config/locales/de.yml b/config/locales/de.yml index 0af899cd..e99e3d83 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -608,6 +608,8 @@ de: own_user_id: "Deine Nutzer-ID:" pair_programming_info: Pair Programming Info work_alone: "Du kannst dich einmalig dafür entscheiden, die Aufgabe alleine zu bearbeiten. Anschließend kannst du jedoch nicht mehr in die Partnerarbeit für diese Aufgabe wechseln. Klicke hier, um die Aufgabe im Einzelmodus zu starten." + implement: + info_disconnected: Ihre Verbindung zum Server wurde unterbrochen. Bitte überprüfen Sie Ihre Internetverbindung und laden Sie die Seite erneut. external_users: statistics: title: Statistiken für Externe Benutzer diff --git a/config/locales/en.yml b/config/locales/en.yml index 50ee74a8..0e3d5c59 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -608,6 +608,8 @@ en: own_user_id: "Your user ID:" pair_programming_info: Pair Programming Info work_alone: "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." + implement: + info_disconnected: You are disconnected from the server. Please check your internet connection and reload the page. external_users: statistics: title: External User Statistics