diff --git a/app/assets/javascripts/submission_statistics.js b/app/assets/javascripts/submission_statistics.js new file mode 100644 index 00000000..75fe42cd --- /dev/null +++ b/app/assets/javascripts/submission_statistics.js @@ -0,0 +1,96 @@ +$(function() { + + var ACE_FILES_PATH = '/assets/ace/'; + var THEME = 'ace/theme/textmate'; + + var currentSubmission = 0; + var active_file = undefined; + var fileTrees = [] + var editor = undefined; + var fileTypeById = {} + + var showActiveFile = function() { + var session = editor.getSession(); + var fileType = fileTypeById[active_file.file_type_id] + session.setMode(fileType.editor_mode); + session.setTabSize(fileType.indent_size); + session.setValue(active_file.content); + session.setUseSoftTabs(true); + session.setUseWrapMode(true); + + showFileTree(currentSubmission); + filetree = $(fileTrees[currentSubmission]) + filetree.jstree("deselect_all"); + filetree.jstree().select_node(active_file.file_id); + }; + + var initializeFileTree = function() { + $('.files').each(function(index, element) { + fileTree = $(element).jstree($(element).data('entries')); + fileTree.on('click', 'li.jstree-leaf', function() { + var id = parseInt($(this).attr('id')) + _.each(files[currentSubmission], function(file) { + if (file.file_id === id) { + active_file = file; + } + }); + showActiveFile(); + }); + fileTrees.push(fileTree); + }); + }; + + var showFileTree = function(index) { + $('.files').hide(); + $(fileTrees[index].context).show(); + } + + if ($.isController('exercises') && $('#timeline').isPresent()) { + + _.each(['modePath', 'themePath', 'workerPath'], function(attribute) { + ace.config.set(attribute, ACE_FILES_PATH); + }); + + var slider = $('#submissions-slider>input'); + var submissions = $('#data').data('submissions'); + var files = $('#data').data('files'); + var filetypes = $('#data').data('file-types'); + + editor = ace.edit('current-file'); + editor.setShowPrintMargin(false); + editor.setTheme(THEME); + editor.$blockScrolling = Infinity; + editor.setReadOnly(true); + + _.each(filetypes, function (filetype) { + filetype = JSON.parse(filetype); + fileTypeById[filetype.id] = filetype; + }); + + $('tr[data-id]>.clickable').each(function(index, element) { + element = $(element); + element.click(function() { + slider.val(index); + slider.change() + }); + }); + + slider.on('change', function(event) { + currentSubmission = slider.val(); + var currentFiles = files[currentSubmission]; + var fileIndex = 0; + _.each(currentFiles, function(file, index) { + if (file.name === active_file.name) { + fileIndex = index; + } + }) + active_file = currentFiles[fileIndex]; + showActiveFile(); + }); + + active_file = files[0][0] + initializeFileTree(); + showActiveFile(); + } + +}); diff --git a/app/assets/stylesheets/statistics.css.scss b/app/assets/stylesheets/statistics.css.scss new file mode 100644 index 00000000..d148f782 --- /dev/null +++ b/app/assets/stylesheets/statistics.css.scss @@ -0,0 +1,12 @@ +#submissions-slider { + margin-top: 25px; + margin-bottom: 25px; +} + +#current-file.editor { + height: 400px; +} + +.clickable { + cursor: pointer; +} diff --git a/app/views/exercises/external_users/statistics.html.slim b/app/views/exercises/external_users/statistics.html.slim index 489a7e21..ca5142cc 100644 --- a/app/views/exercises/external_users/statistics.html.slim +++ b/app/views/exercises/external_users/statistics.html.slim @@ -1 +1,48 @@ -h1 = "#{@exercise} for external user #{@external_user}" \ No newline at end of file +h1 = "#{@exercise} (external user #{@external_user})" +- submissions = Submission.where("user_id = ? AND exercise_id = ?", @external_user.id, @exercise.id) +- current_submission = submissions.first +- if current_submission + - initial_files = current_submission.files.to_a + + - all_files = [] + - file_types = Set.new() + - submissions.each do |submission| + - submission.files.each do |file| + - file_types.add(ActiveSupport::JSON.encode(file.file_type)) + - all_files.push(submission.files) + + .hidden#data data-submissions=ActiveSupport::JSON.encode(submissions) data-files=ActiveSupport::JSON.encode(all_files) data-file-types=ActiveSupport::JSON.encode(file_types) + + #stats-editor.row + - index = 0 + - all_files.each do |files| + .files class=(@exercise.hide_file_tree ? 'hidden col-sm-3' : 'col-sm-3') data-index=index data-entries=FileTree.new(files).to_js_tree + - index += 1 + div class=(@exercise.hide_file_tree ? 'col-sm-12' : 'col-sm-9') + #current-file.editor + + #submissions-slider + input type='range' orient='horizontal' list='datapoints' min=0 max=submissions.length-1 value=0 + datalist#datapoints + - index=0 + - submissions.each do |submission| + option data-submission=submission + =index + - index += 1 + + #timeline + .table-responsive + table.table + thead + tr + - ['.time', '.cause', '.score'].each do |title| + th.header = t(title) + tbody + - submissions.each do |submission| + tr data-id=submission.id + td.clickable = submission.created_at.strftime("%F %T") + td = submission.cause + td = submission.score + +- else + p = t('.no_data_available') diff --git a/config/locales/de.yml b/config/locales/de.yml index bbd0e5de..525b65ae 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -253,6 +253,12 @@ de: external_user: Externe Nutzer submit: failure: Beim Übermitteln Ihrer Punktzahl ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut. + external_users: + statistics: + no_data_available: Keine Daten verfügbar. + time: Zeit + cause: Grund + score: Punktzahl files: roles: main_file: Hauptdatei diff --git a/config/locales/en.yml b/config/locales/en.yml index fc08792a..47539bf1 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -253,6 +253,12 @@ en: external_users: External Users submit: failure: An error occured while transmitting your score. Please try again later. + external_users: + statistics: + no_data_available: No data available. + time: Time + cause: Cause + score: Score files: roles: main_file: Main File