Merge remote-tracking branch 'origin/master' into flowr
# Conflicts: # app/assets/javascripts/editor/evaluation.js # app/assets/javascripts/editor/participantsupport.js # app/views/exercises/_editor_output.html.slim # config/code_ocean.yml.example # config/routes.rb
This commit is contained in:
@@ -33,6 +33,7 @@ var CodeOceanEditor = {
|
||||
<% @config ||= CodeOcean::Config.new(:code_ocean).read(erb: false) %>
|
||||
sendEvents: <%= @config['codeocean_events'] ? @config['codeocean_events']['enabled'] : false %>,
|
||||
eventURL: "<%= @config['codeocean_events'] ? events_path : '' %>",
|
||||
fileTypeURL: "<%= file_types_path %>",
|
||||
|
||||
|
||||
configureEditors: function () {
|
||||
@@ -43,7 +44,7 @@ configureEditors: function () {
|
||||
|
||||
confirmDestroy: function (event) {
|
||||
event.preventDefault();
|
||||
if (confirm($(this).data('message-confirm'))) {
|
||||
if (confirm($(event.target).data('message-confirm'))) {
|
||||
this.destroyFile();
|
||||
}
|
||||
},
|
||||
@@ -63,7 +64,7 @@ configureEditors: function () {
|
||||
if ($('#output-' + index).isPresent()) {
|
||||
return $('#output-' + index);
|
||||
} else {
|
||||
var element = $('<pre>').attr('id', 'output-' + index);
|
||||
var element = $('<pre class="mt-2">').attr('id', 'output-' + index);
|
||||
$('#output').append(element);
|
||||
return element;
|
||||
}
|
||||
@@ -79,13 +80,13 @@ configureEditors: function () {
|
||||
}
|
||||
},
|
||||
|
||||
getPanelClass: function (result) {
|
||||
getCardClass: function (result) {
|
||||
if (result.stderr && !result.score) {
|
||||
return 'panel-danger';
|
||||
return 'card bg-danger text-white';
|
||||
} else if (result.score < 1) {
|
||||
return 'panel-warning';
|
||||
return 'card bg-warning text-white';
|
||||
} else {
|
||||
return 'panel-success';
|
||||
return 'card bg-success text-white';
|
||||
}
|
||||
},
|
||||
|
||||
@@ -107,11 +108,22 @@ configureEditors: function () {
|
||||
progress_bar.css('width', percentage + '%');
|
||||
},
|
||||
|
||||
// The event ready.jstree is fired too early and thus doesn't work.
|
||||
selectFileInJsTree: function(filetree, file_id) {
|
||||
if (!filetree.hasClass('jstree-loading')) {
|
||||
filetree.jstree("deselect_all");
|
||||
filetree.jstree().select_node(file_id);
|
||||
} else {
|
||||
setTimeout(this.selectFileInJsTree.bind(null, filetree, file_id), 250);
|
||||
}
|
||||
},
|
||||
|
||||
showFirstFile: function() {
|
||||
var frame = $('.frame[data-role="main_file"]').isPresent() ? $('.frame[data-role="main_file"]') : $('.frame').first();
|
||||
var file_id = frame.find('.editor').data('file-id');
|
||||
this.setActiveFile(frame.data('filename'), file_id);
|
||||
$('#files').jstree().select_node(file_id);
|
||||
var filetree = $('#files');
|
||||
this.selectFileInJsTree(filetree, file_id);
|
||||
this.showFrame(frame);
|
||||
this.toggleButtonStates();
|
||||
},
|
||||
@@ -124,11 +136,11 @@ configureEditors: function () {
|
||||
|
||||
getProgressBarClass: function (percentage) {
|
||||
if (percentage < this.ADEQUATE_PERCENTAGE) {
|
||||
return 'progress-bar progress-bar-striped progress-bar-danger';
|
||||
return 'progress-bar progress-bar-striped bg-danger';
|
||||
} else if (percentage < this.SUCCESSFULL_PERCENTAGE) {
|
||||
return 'progress-bar progress-bar-striped progress-bar-warning';
|
||||
return 'progress-bar progress-bar-striped bg-warning';
|
||||
} else {
|
||||
return 'progress-bar progress-bar-striped progress-bar-success';
|
||||
return 'progress-bar progress-bar-striped bg-success';
|
||||
}
|
||||
},
|
||||
|
||||
@@ -158,7 +170,7 @@ configureEditors: function () {
|
||||
category: 'editor_paste',
|
||||
data: pasteObject.text,
|
||||
exercise_id: $('#editor').data('exercise-id'),
|
||||
file_id: $(this).data('file-id')
|
||||
file_id: $(event.target).data('file-id')
|
||||
});
|
||||
}
|
||||
},
|
||||
@@ -177,8 +189,8 @@ configureEditors: function () {
|
||||
},
|
||||
|
||||
resizeParentOfAceEditor: function (element){
|
||||
// calculate needed size: window height - position of top of button-bar - 60 for bar itself and margins
|
||||
var windowHeight = window.innerHeight - $('#editor-buttons').offset().top - 60;
|
||||
// calculate needed size: window height - position of top of ACE editor - height of autosave label below editor - 5 for bar margins
|
||||
var windowHeight = window.innerHeight - $(element).offset().top - $('#autosave-label').height() - 5;
|
||||
$(element).parent().height(windowHeight);
|
||||
},
|
||||
|
||||
@@ -266,14 +278,29 @@ configureEditors: function () {
|
||||
this.initializeRequestForComments()
|
||||
},
|
||||
|
||||
updateEditorModeToFileTypeID: function (editor, fileTypeID) {
|
||||
var newMode = 'ace/mode/text'
|
||||
|
||||
$.ajax(this.fileTypeURL + '/' + fileTypeID, {
|
||||
dataType: 'json'
|
||||
}).done(function (data) {
|
||||
if (data['editor_mode'] !== null) {
|
||||
newMode = data['editor_mode'];
|
||||
}
|
||||
}).fail(_.noop)
|
||||
.always(function () {
|
||||
ace.edit(editor).session.setMode(newMode);
|
||||
});
|
||||
},
|
||||
|
||||
initializeFileTree: function () {
|
||||
$('#files').jstree($('#files').data('entries'));
|
||||
$('#files').on('click', 'li.jstree-leaf', function (event) {
|
||||
active_file = {
|
||||
filename: $(event.target).parent().text(),
|
||||
id: parseInt($(event.target).parent().attr('id'))
|
||||
};
|
||||
var frame = $('[data-file-id="' + active_file.id + '"]').parent();
|
||||
this.setActiveFile(
|
||||
$(event.target).parent().text(),
|
||||
parseInt($(event.target).parent().attr('id'))
|
||||
);
|
||||
var frame = $('[data-file-id="' + this.active_file.id + '"]').parent();
|
||||
this.showFrame(frame);
|
||||
this.toggleButtonStates();
|
||||
}.bind(this));
|
||||
@@ -296,8 +323,8 @@ configureEditors: function () {
|
||||
|
||||
handleSideBarToggle: function() {
|
||||
$('#sidebar').toggleClass('sidebar-col').toggleClass('sidebar-col-collapsed');
|
||||
$('#sidebar-collapsed').toggleClass('hidden');
|
||||
$('#sidebar-uncollapsed').toggleClass('hidden');
|
||||
$('#sidebar-collapsed').toggleClass('d-none');
|
||||
$('#sidebar-uncollapsed').toggleClass('d-none');
|
||||
},
|
||||
|
||||
initializeRegexes: function () {
|
||||
@@ -369,17 +396,17 @@ configureEditors: function () {
|
||||
return Modernizr.websockets;
|
||||
},
|
||||
|
||||
populatePanel: function (panel, result, index) {
|
||||
panel.removeClass('panel-default').addClass(this.getPanelClass(result));
|
||||
panel.find('.panel-title .filename').text(result.filename);
|
||||
panel.find('.panel-title .number').text(index + 1);
|
||||
panel.find('.row .col-sm-9').eq(0).find('.number').eq(0).text(result.passed);
|
||||
panel.find('.row .col-sm-9').eq(0).find('.number').eq(1).text(result.count);
|
||||
panel.find('.row .col-sm-9').eq(1).find('.number').eq(0).text(parseFloat((result.score * result.weight).toFixed(2)));
|
||||
panel.find('.row .col-sm-9').eq(1).find('.number').eq(1).text(result.weight);
|
||||
panel.find('.row .col-sm-9').eq(2).html(result.message);
|
||||
if (result.error_messages) panel.find('.row .col-sm-9').eq(3).text(result.error_messages.join(' '));
|
||||
//panel.find('.row .col-sm-9').eq(4).find('a').attr('href', '#output-' + index);
|
||||
populateCard: function (card, result, index) {
|
||||
card.addClass(this.getCardClass(result));
|
||||
card.find('.card-title .filename').text(result.filename);
|
||||
card.find('.card-title .number').text(index + 1);
|
||||
card.find('.row .col-sm-9').eq(0).find('.number').eq(0).text(result.passed);
|
||||
card.find('.row .col-sm-9').eq(0).find('.number').eq(1).text(result.count);
|
||||
card.find('.row .col-sm-9').eq(1).find('.number').eq(0).text(parseFloat((result.score * result.weight).toFixed(2)));
|
||||
card.find('.row .col-sm-9').eq(1).find('.number').eq(1).text(result.weight);
|
||||
card.find('.row .col-sm-9').eq(2).html(result.message);
|
||||
if (result.error_messages) card.find('.row .col-sm-9').eq(3).text(result.error_messages.join(' '));
|
||||
//card.find('.row .col-sm-9').eq(4).find('a').attr('href', '#output-' + index);
|
||||
},
|
||||
|
||||
publishCodeOceanEvent: function (payload) {
|
||||
@@ -409,7 +436,7 @@ configureEditors: function () {
|
||||
url: $('#editor').data('errors-url')
|
||||
});
|
||||
jqxhr.always(this.hideSpinner);
|
||||
jqxhr.success(this.renderHint);
|
||||
jqxhr.done(this.renderHint);
|
||||
},
|
||||
|
||||
toggleButtonStates: function () {
|
||||
@@ -556,14 +583,14 @@ configureEditors: function () {
|
||||
},
|
||||
|
||||
showOutputBar: function() {
|
||||
$('#output_sidebar_collapsed').addClass('hidden');
|
||||
$('#output_sidebar_uncollapsed').removeClass('hidden');
|
||||
$('#output_sidebar_collapsed').addClass('d-none');
|
||||
$('#output_sidebar_uncollapsed').removeClass('d-none');
|
||||
$('#output_sidebar').removeClass('output-col-collapsed').addClass('output-col');
|
||||
},
|
||||
|
||||
hideOutputBar: function() {
|
||||
$('#output_sidebar_collapsed').removeClass('hidden');
|
||||
$('#output_sidebar_uncollapsed').addClass('hidden');
|
||||
$('#output_sidebar_collapsed').removeClass('d-none');
|
||||
$('#output_sidebar_uncollapsed').addClass('d-none');
|
||||
$('#output_sidebar').removeClass('output-col').addClass('output-col-collapsed');
|
||||
},
|
||||
|
||||
@@ -572,16 +599,17 @@ configureEditors: function () {
|
||||
},
|
||||
|
||||
initializeDescriptionToggle: function() {
|
||||
$('#exercise-headline').on('click', this.toggleDescriptionPanel.bind(this));
|
||||
$('a#toggle').on('click', this.toggleDescriptionPanel.bind(this));
|
||||
$('#exercise-headline').on('click', this.toggleDescriptionCard.bind(this));
|
||||
$('a#toggle').on('click', this.toggleDescriptionCard.bind(this));
|
||||
},
|
||||
|
||||
toggleDescriptionPanel: function() {
|
||||
$('#description-panel').toggleClass('description-panel-collapsed').toggleClass('description-panel');
|
||||
toggleDescriptionCard: function() {
|
||||
$('#description-card').toggleClass('description-card-collapsed').toggleClass('description-card');
|
||||
$('#description-symbol').toggleClass('fa-chevron-down').toggleClass('fa-chevron-right');
|
||||
var toggle = $('a#toggle');
|
||||
toggle.text(toggle.text() == toggle.data('hide') ? toggle.data('show') : toggle.data('hide'));
|
||||
this.resizeAceEditors();
|
||||
event.preventDefault();
|
||||
},
|
||||
|
||||
/**
|
||||
|
@@ -9,7 +9,7 @@ CodeOceanEditorEvaluation = {
|
||||
this.clearScoringOutput();
|
||||
this.createSubmission('#assess', null, function (response) {
|
||||
this.showSpinner($('#assess'));
|
||||
$('#score_div').removeClass('hidden');
|
||||
$('#score_div').removeClass('d-none');
|
||||
var url = response.score_url;
|
||||
this.initializeSocketForScoring(url);
|
||||
}.bind(this));
|
||||
@@ -26,9 +26,9 @@ CodeOceanEditorEvaluation = {
|
||||
|
||||
printScoringResult: function (result, index) {
|
||||
$('#results').show();
|
||||
var panel = $('#dummies').children().first().clone();
|
||||
this.populatePanel(panel, result, index);
|
||||
$('#results ul').first().append(panel);
|
||||
var card = $('#dummies').children().first().clone();
|
||||
this.populateCard(card, result, index);
|
||||
$('#results ul').first().append(card);
|
||||
},
|
||||
|
||||
printScoringResults: function (response) {
|
||||
@@ -60,7 +60,7 @@ CodeOceanEditorEvaluation = {
|
||||
renderHint: function (object) {
|
||||
var hint = object.data || object.hint;
|
||||
if (hint) {
|
||||
$('#hint .panel-body').text(hint);
|
||||
$('#hint .card-body').text(hint);
|
||||
$('#hint').fadeIn();
|
||||
}
|
||||
},
|
||||
@@ -152,22 +152,22 @@ CodeOceanEditorEvaluation = {
|
||||
var element = this.findOrCreateOutputElement(index);
|
||||
if (!colorize) {
|
||||
if (output.stdout != undefined && output.stdout != '') {
|
||||
element.append(output.stdout)
|
||||
//element.text(element.text() + output.stdout)
|
||||
//element.append(output.stdout)
|
||||
element.text(element.text() + output.stdout)
|
||||
}
|
||||
|
||||
if (output.stderr != undefined && output.stderr != '') {
|
||||
element.append('StdErr: ' + output.stderr);
|
||||
//element.text('StdErr: ' + element.text() + output.stderr);
|
||||
//element.append('StdErr: ' + output.stderr);
|
||||
element.text('StdErr: ' + element.text() + output.stderr);
|
||||
}
|
||||
|
||||
} else if (output.stderr) {
|
||||
element.addClass('text-warning').append(output.stderr);
|
||||
//element.addClass('text-warning').text(element.text() + output.stderr);
|
||||
//element.addClass('text-warning').append(output.stderr);
|
||||
element.addClass('text-warning').text(element.text() + output.stderr);
|
||||
this.QaApiOutputBuffer.stderr += output.stderr;
|
||||
} else if (output.stdout) {
|
||||
element.addClass('text-success').append(output.stdout);
|
||||
//element.addClass('text-success').text(element.text() + output.stdout);
|
||||
//element.addClass('text-success').append(output.stdout);
|
||||
element.addClass('text-success').text(element.text() + output.stdout);
|
||||
this.QaApiOutputBuffer.stdout += output.stdout;
|
||||
} else {
|
||||
element.addClass('text-muted').text($('#output').data('message-no-output'));
|
@@ -2,8 +2,9 @@ CodeOceanEditorWebsocket = {
|
||||
websocket: null,
|
||||
|
||||
createSocketUrl: function(url) {
|
||||
var sockURL = new URL(window.location);
|
||||
sockURL.pathname = url;
|
||||
var sockURL = new URL(url, window.location);
|
||||
// not needed any longer, we put it directly into the url: sockURL.pathname = url;
|
||||
|
||||
// sanitize socket protocol string, strip trailing slash and other malicious chars if they are there
|
||||
sockURL.protocol = '<%= DockerClient.config['ws_client_protocol']&.match(/(\w+):*\/*/)&.to_a&.at(1) %>:';
|
||||
|
||||
|
@@ -90,7 +90,6 @@ CodeOceanEditorFlowr = {
|
||||
var collapsibleTileHtml = self.flowrResultHtml
|
||||
.replace(/{{collapseId}}/g, 'collapse-' + index).replace(/{{headingId}}/g, 'heading-' + index);
|
||||
var resultTile = $(collapsibleTileHtml);
|
||||
|
||||
var questionUrl = 'https://stackoverflow.com/questions/' + result.question_id;
|
||||
|
||||
var header = resultTile.find('h4 > a');
|
||||
@@ -162,7 +161,7 @@ CodeOceanEditorRequestForComments = {
|
||||
$.flash.success({text: $('#askForCommentsButton').data('message-success')});
|
||||
// trigger a run
|
||||
this.runSubmission.call(this, submission);
|
||||
}.bind(this)).error(this.ajaxError.bind(this));
|
||||
}.bind(this)).fail(this.ajaxError.bind(this));
|
||||
};
|
||||
|
||||
this.createSubmission($('#requestComments'), null, createRequestForComments.bind(this));
|
||||
|
@@ -2,19 +2,19 @@ CodeOceanEditorPrompt = {
|
||||
prompt: '#prompt',
|
||||
|
||||
showPrompt: function(msg) {
|
||||
var label = $('#prompt .input-group-addon');
|
||||
var label = $('#prompt .input-group-text');
|
||||
var prompt = $(this.prompt);
|
||||
label.text(msg.data || label.data('prompt'));
|
||||
if (prompt.isPresent() && prompt.hasClass('hidden')) {
|
||||
prompt.removeClass('hidden');
|
||||
if (prompt.isPresent() && prompt.hasClass('d-none')) {
|
||||
prompt.removeClass('d-none');
|
||||
}
|
||||
$('#prompt input').focus();
|
||||
},
|
||||
|
||||
hidePrompt: function() {
|
||||
var prompt = $(this.prompt);
|
||||
if (prompt.isPresent() && !prompt.hasClass('hidden')) {
|
||||
prompt.addClass('hidden');
|
||||
if (prompt.isPresent() && !prompt.hasClass('d-none')) {
|
||||
prompt.addClass('d-none');
|
||||
}
|
||||
},
|
||||
|
@@ -106,14 +106,16 @@ CodeOceanEditorSubmissions = {
|
||||
this.ajax({
|
||||
method: 'GET',
|
||||
url: $('#start-over').data('url')
|
||||
}).success(function(response) {
|
||||
}).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;
|
||||
});
|
||||
editor.setValue(file.content);
|
||||
if(file){
|
||||
editor.setValue(file.content);
|
||||
}
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
},
|
||||
@@ -153,7 +155,7 @@ CodeOceanEditorSubmissions = {
|
||||
$('#stop').data('url', submission.stop_url);
|
||||
this.running = true;
|
||||
this.showSpinner($('#run'));
|
||||
$('#score_div').addClass('hidden');
|
||||
$('#score_div').addClass('d-none');
|
||||
this.toggleButtonStates();
|
||||
var url = submission.run_url.replace(this.FILENAME_URL_PLACEHOLDER, this.active_file.filename.replace(/#$/,'')); // remove # if it is the last character, this is not part of the filename and just an anchor
|
||||
this.initializeSocketForRunning(url);
|
||||
@@ -173,8 +175,8 @@ CodeOceanEditorSubmissions = {
|
||||
if ($('#test').is(':visible')) {
|
||||
this.createSubmission('#test', null, function(response) {
|
||||
this.showSpinner($('#test'));
|
||||
$('#score_div').addClass('hidden');
|
||||
var url = response.test_url.replace(this.FILENAME_URL_PLACEHOLDER, this.active_file.filenamereplace(/#$/,'')); // remove # if it is the last character, this is not part of the filename and just an anchor
|
||||
$('#score_div').addClass('d-none');
|
||||
var url = response.test_url.replace(this.FILENAME_URL_PLACEHOLDER, this.active_file.filename.replace(/#$/,'')); // remove # if it is the last character, this is not part of the filename and just an anchor
|
||||
this.initializeSocketForTesting(url);
|
||||
}.bind(this));
|
||||
}
|
@@ -38,10 +38,10 @@ CodeOceanEditorTurtle = {
|
||||
|
||||
showCanvas: function () {
|
||||
if ($('#turtlediv').isPresent()
|
||||
&& this.turtlecanvas.hasClass('hidden')) {
|
||||
&& this.turtlecanvas.hasClass('d-none')) {
|
||||
// initialize two-column layout
|
||||
$('#output-col1').addClass('col-lg-7 col-md-7 two-column');
|
||||
this.turtlecanvas.removeClass('hidden');
|
||||
this.turtlecanvas.removeClass('d-none');
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user