diff --git a/app/assets/javascripts/editor.js b/app/assets/javascripts/editor.js index ddbbc36e..b9ca3017 100644 --- a/app/assets/javascripts/editor.js +++ b/app/assets/javascripts/editor.js @@ -11,6 +11,7 @@ $(function() { var FILENAME_URL_PLACEHOLDER = '{filename}'; var SUCCESSFULL_PERCENTAGE = 90; var THEME = 'ace/theme/textmate'; + var AUTOSAVE_INTERVAL = 15 * 1000; var editors = []; var active_file = undefined; @@ -341,6 +342,23 @@ $(function() { $('button i.fa-spin').hide(); }; + var autosaveTimer; + var autosaveLabel = $("#autosave-label span"); + + var resetSaveTimer = function(){ + clearTimeout(autosaveTimer); + autosaveTimer = setTimeout(autosave, AUTOSAVE_INTERVAL); + }; + + var autosave = function(){ + var date = new Date(); + autosaveLabel.parent().css("visibility", "visible"); + autosaveLabel.text(date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds()); + autosaveLabel.text(date.toLocaleTimeString()); + autosaveTimer = null; + createSubmission($('#autosave'), null); + } + var initializeEditors = function() { $('.editor').each(function(index, element) { var editor = ace.edit(element); @@ -350,6 +368,12 @@ $(function() { }); } + + // listener for autosave + editor.getSession().on("change", function (deltaObject) { + resetSaveTimer(); + }); + var document = editor.getSession().getDocument(); // insert pre-existing code into editor. we have to use insertLines, otherwise the deltas are not properly added var file_id = $(element).data('file-id'); @@ -875,12 +899,14 @@ $(function() { icon: ['fa', 'fa-bug'], text: $('#run').data('message-failure') }); - } else { + } + /* do not show the success message any longer, puzzles and distracts users. + else { $.flash.success({ icon: ['fa', 'fa-check'], text: $('#run').data('message-success') }); - } + } */ }; var showContainerDepletedMessage = function() { @@ -1020,6 +1046,13 @@ $(function() { } } + $(window).on("beforeunload", function() { + if(autosaveTimer){ + autosave(); + } + + }) + if ($('#editor').isPresent()) { if (isBrowserSupported()) { initializeCodePilot(); diff --git a/app/assets/stylesheets/editor.css.scss b/app/assets/stylesheets/editor.css.scss index b2ad8f36..efcf1d25 100644 --- a/app/assets/stylesheets/editor.css.scss +++ b/app/assets/stylesheets/editor.css.scss @@ -31,7 +31,7 @@ button i.fa-spin { #editor-buttons { background-color: #008CBA; - margin-top: 1em; + margin-top: 0; width: 100%; button { @@ -39,7 +39,7 @@ button i.fa-spin { } button, .btn-group { - width: 25%; + width: 33.33333%; } .btn-group { @@ -80,3 +80,11 @@ button i.fa-spin { #results { display: none; } + +#autosave-label{ + visibility: hidden; + height: 1.6em; + text-align: right; + color: #777; + font-size: 0.8em; +} diff --git a/app/models/submission.rb b/app/models/submission.rb index 70ceece8..16ca74dc 100644 --- a/app/models/submission.rb +++ b/app/models/submission.rb @@ -2,7 +2,7 @@ class Submission < ActiveRecord::Base include Context include Creation - CAUSES = %w(assess download file render run save submit test) + CAUSES = %w(assess download file render run save submit test autosave) FILENAME_URL_PLACEHOLDER = '{filename}' belongs_to :exercise diff --git a/app/views/exercises/_editor.html.slim b/app/views/exercises/_editor.html.slim index 0794cb41..986af92d 100644 --- a/app/views/exercises/_editor.html.slim +++ b/app/views/exercises/_editor.html.slim @@ -3,9 +3,13 @@ #frames.col-sm-9 - @files.each do |file| = render('editor_frame', exercise: exercise, file: file) + #autosave-label + = t('exercises.editor.lastsaved') + span #editor-buttons.btn-group = render('editor_button', data: {:'data-message-confirm' => t('exercises.editor.confirm_start_over'), :'data-url' => reload_exercise_path(exercise)}, icon: 'fa fa-history', id: 'start-over', label: t('exercises.editor.start_over')) - = render('editor_button', data: {:'data-message-success' => t('submissions.create.success'), :'data-placement' => 'top', :'data-tooltip' => true}, icon: 'fa fa-save', id: 'save', label: t('exercises.editor.save'), title: t('.tooltips.save')) + // = render('editor_button', data: {:'data-message-success' => t('submissions.create.success'), :'data-placement' => 'top', :'data-tooltip' => true}, icon: 'fa fa-save', id: 'save', label: t('exercises.editor.save'), title: t('.tooltips.save')) + button style="display:none" id="autosave" .btn-group = render('editor_button', disabled: true, icon: 'fa fa-ban', id: 'dummy', label: t('exercises.editor.dummy')) = render('editor_button', icon: 'fa fa-desktop', id: 'render', label: t('exercises.editor.render')) diff --git a/config/locales/de.yml b/config/locales/de.yml index 0afedb79..e7fe1857 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -170,11 +170,12 @@ de: destroy_file: Datei löschen download: Herunterladen dummy: Keine Aktion + lastsaved: 'Zuletzt gespeichert: ' network: 'Während Ihr Code läuft, ist Port %{port} unter folgender Adresse erreichbar: %{address}.' render: Anzeigen run: Ausführen - run_failure: Bei der Ausführung Ihres Codes sind Fehler aufgetreten. - run_success: Ihr Code wurde fehlerfrei ausgeführt. + run_failure: Ihr Code konnte nicht auf der Plattform ausgeführt werden. + run_success: Ihr Code wurde auf der Plattform ausgeführt. requestComments: Rückmeldung erbitten save: Speichern score: Bewerten diff --git a/config/locales/en.yml b/config/locales/en.yml index c762a01b..52d4ceb3 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -170,11 +170,12 @@ en: destroy_file: Delete File download: Download dummy: No Action + lastsaved: 'Last saved: ' network: 'While your code is running, port %{port} is accessible using the following address: %{address}.' render: Render run: Run - run_failure: Your code ran with errors. - run_success: Your code ran without errors. + run_failure: Your code could not be run. + run_success: Your code was run on our servers. requestComments: Request comments save: Save score: Score