after merge

This commit is contained in:
yqbk
2016-08-03 11:22:39 +02:00
60 changed files with 457 additions and 423 deletions

View File

@@ -19,6 +19,10 @@ $(function() {
var SERVER_SEND_EVENT = 2;
var editors = [];
var editor_for_file = new Map();
var regex_for_language = new Map();
var tracepositions_regex;
var active_file = undefined;
var active_frame = undefined;
var running = false;
@@ -37,6 +41,7 @@ $(function() {
var ENTER_KEY_CODE = 13;
var flowrOutputBuffer = "";
var QaApiOutputBuffer = {'stdout': '', 'stderr': ''};
var flowrResultHtml = '<div class="panel panel-default"><div id="{{headingId}}" role="tab" class="panel-heading"><h4 class="panel-title"><a data-toggle="collapse" data-parent="#flowrHint" href="#{{collapseId}}" aria-expanded="true" aria-controls="{{collapseId}}"></a></h4></div><div id="{{collapseId}}" role="tabpanel" aria-labelledby="{{headingId}}" class="panel-collapse collapse"><div class="panel-body"></div></div></div>'
var ajax = function(options) {
@@ -175,7 +180,10 @@ $(function() {
var downloadCode = function(event) {
event.preventDefault();
createSubmission(this, null,function(response) {
var url = response.download_url.replace(FILENAME_URL_PLACEHOLDER, active_file.filename);
var url = response.download_url;
// to download just a single file, use the following url
//var url = response.download_file_url.replace(FILENAME_URL_PLACEHOLDER, active_file.filename);
window.location = url;
});
};
@@ -184,8 +192,8 @@ $(function() {
(streamed ? evaluateCodeWithStreamedResponse : evaluateCodeWithoutStreamedResponse)(url, callback);
};
var evaluateCodeWithStreamedResponse = function(url, callback) {
initWebsocketConnection(url);
var evaluateCodeWithStreamedResponse = function(url, onmessageFunction) {
initWebsocketConnection(url, onmessageFunction);
// TODO only init turtle when required
initTurtle();
@@ -306,9 +314,10 @@ $(function() {
}
};
var handleScoringResponse = function(response) {
printScoringResults(response);
var score = _.reduce(response, function(sum, result) {
var handleScoringResponse = function(websocket_event) {
results = JSON.parse(websocket_event.data);
printScoringResults(results);
var score = _.reduce(results, function(sum, result) {
return sum + result.score * result.weight;
}, 0).toFixed(2);
$('#score').data('score', score);
@@ -316,6 +325,14 @@ $(function() {
showTab(2);
};
var handleQaApiOutput = function() {
if (qa_api) {
qa_api.executeCommand('syncOutput', [[QaApiOutputBuffer]]);
// reset the object
}
QaApiOutputBuffer = {'stdout': '', 'stderr': ''};
}
// activate flowr only for half of the audience
var isFlowrEnabled = true;//parseInt($('#editor').data('user-id'))%2 == 0;
var handleStderrOutputForFlowr = function() {
@@ -349,13 +366,14 @@ $(function() {
flowrOutputBuffer = '';
};
var handleTestResponse = function(response) {
var handleTestResponse = function(websocket_event) {
result = JSON.parse(websocket_event.data);
clearOutput();
printOutput(response[0], false, 0);
printOutput(result, false, 0);
if (qa_api) {
qa_api.executeCommand('syncOutput', [response]);
qa_api.executeCommand('syncOutput', [result]);
}
showStatus(response[0]);
showStatus(result);
showTab(1);
};
@@ -404,12 +422,18 @@ $(function() {
editor.setTheme(THEME);
editor.commands.bindKey("ctrl+alt+0", null);
editors.push(editor);
editor_for_file.set($(element).parent().data('filename'), editor);
var session = editor.getSession();
session.setMode($(element).data('mode'));
session.setTabSize($(element).data('indent-size'));
session.setUseSoftTabs(true);
session.setUseWrapMode(true);
// set regex for parsing error traces based on the mode of the main file.
if( $(element).parent().data('role') == "main_file"){
tracepositions_regex = regex_for_language.get($(element).data('mode'));
}
var file_id = $(element).data('id');
/*
@@ -457,6 +481,12 @@ $(function() {
$('#request-for-comments').on('click', requestComments);
};
var initializeRegexes = function(){
regex_for_language.set("ace/mode/python", /File "(.+?)", line (\d+)/g);
regex_for_language.set("ace/mode/java", /(.*\.java):(\d+):/g);
}
var initializeTooltips = function() {
$('[data-tooltip]').tooltip();
};
@@ -527,8 +557,8 @@ $(function() {
};
var isBrowserSupported = function() {
// eventsource tests for server send events (used for scoring), websockets is used for run
return Modernizr.eventsource && Modernizr.websockets;
// websockets is used for run, score and test
return Modernizr.websockets;
};
var populatePanel = function(panel, result, index) {
@@ -574,20 +604,23 @@ $(function() {
// output_mode_is_streaming = false;
//}
if (!colorize) {
if(output.stdout != ''){
if(output.stdout != undefined && output.stdout != ''){
element.append(output.stdout)
}
if(output.stderr != ''){
if(output.stderr != undefined && output.stderr != ''){
element.append('There was an error: StdErr: ' + output.stderr);
}
} else if (output.stderr) {
element.addClass('text-warning').append(output.stderr);
flowrOutputBuffer += output.stderr;
QaApiOutputBuffer.stderr += output.stderr;
} else if (output.stdout) {
//if (output_mode_is_streaming){
element.addClass('text-success').append(output.stdout);
flowrOutputBuffer += output.stdout;
QaApiOutputBuffer.stdout += output.stdout;
//}else{
// element.addClass('text-success');
// element.data('content_buffer' , element.data('content_buffer') + output.stdout);
@@ -743,7 +776,7 @@ $(function() {
showSpinner($('#run'));
toggleButtonStates();
var url = response.run_url.replace(FILENAME_URL_PLACEHOLDER, active_file.filename);
evaluateCode(url, true, printChunk);
evaluateCode(url, true, function(evt) { parseCanvasMessage(evt.data, true); });
});
}
};
@@ -778,7 +811,7 @@ $(function() {
createSubmission(this, null, function(response) {
showSpinner($('#assess'));
var url = response.score_url;
evaluateCode(url, false, handleScoringResponse);
evaluateCode(url, true, handleScoringResponse);
});
};
@@ -876,7 +909,9 @@ $(function() {
}
var showWorkspaceTab = function(event) {
event.preventDefault();
if(event){
event.preventDefault();
}
showTab(0);
};
@@ -955,7 +990,7 @@ $(function() {
createSubmission(this, null, function(response) {
showSpinner($('#test'));
var url = response.test_url.replace(FILENAME_URL_PLACEHOLDER, active_file.filename);
evaluateCode(url, false, handleTestResponse);
evaluateCode(url, true, handleTestResponse);
});
}
};
@@ -974,14 +1009,14 @@ $(function() {
$('#test').toggle(isActiveFileTestable());
};
var initWebsocketConnection = function(url) {
var initWebsocketConnection = function(url, onmessageFunction) {
//TODO: get the protocol from config file dependent on environment. (dev: ws, prod: wss)
//causes: Puma::HttpParserError: Invalid HTTP format, parsing fails.
//TODO: make sure that this gets cached.
websocket = new WebSocket('<%= DockerClient.config['ws_client_protocol'] %>' + window.location.hostname + ':' + window.location.port + url);
websocket.onopen = function(evt) { resetOutputTab(); }; // todo show some kind of indicator for established connection
websocket.onclose = function(evt) { /* expected at some point */ };
websocket.onmessage = function(evt) { parseCanvasMessage(evt.data, true); };
websocket.onmessage = onmessageFunction;
websocket.onerror = function(evt) { showWebsocketError(); };
websocket.flush = function() { this.send('\n'); }
};
@@ -1035,7 +1070,9 @@ $(function() {
break;
case 'exit':
killWebsocketAndContainer();
handleQaApiOutput();
handleStderrOutputForFlowr();
augmentStacktraceInOutput();
break;
case 'timeout':
// just show the timeout message here. Another exit command is sent by the rails backend when the socket to the docker container closes.
@@ -1047,6 +1084,41 @@ $(function() {
}
};
var jumpToSourceLine = function(event){
var file = $(event.target).data('file');
var line = $(event.target).data('line');
showWorkspaceTab(null);
// set active file ?!?!
var frame = $('div.frame[data-filename="' + file + '"]');
showFrame(frame);
var editor = editor_for_file.get(file);
editor.gotoLine(line, 0);
};
var augmentStacktraceInOutput = function() {
if(tracepositions_regex){
var element = $('#output>pre');
var text = element.text();
element.on( "click", "a", jumpToSourceLine);
var matches;
while(matches = tracepositions_regex.exec(text)){
var frame = $('div.frame[data-filename="' + matches[1] + '"]')
if(frame.length > 0){
element.html(text.replace(matches[0], "<a href='#' data-file='" + matches[1] + "' data-line='" + matches[2] + "'>" + matches[0] + "</a>"));
}
}
}
};
var renderWebsocketOutput = function(msg){
var element = findOrCreateRenderElement(0);
element.append(msg.data);
@@ -1160,25 +1232,25 @@ $(function() {
var file_id = $('.editor').data('id')
var question = $('#question').val();
$.ajax({
method: 'POST',
url: '/request_for_comments',
data: {
request_for_comment: {
exercise_id: exercise_id,
file_id: file_id,
question: question,
"requested_at(1i)": 2015, // these are the timestamp values that the request handler demands
"requested_at(2i)":3, // they could be random here, because the timestamp is updated on serverside anyway
"requested_at(3i)":27,
"requested_at(4i)":17,
"requested_at(5i)":06
var createRequestForComments = function(submission) {
$.ajax({
method: 'POST',
url: '/request_for_comments',
data: {
request_for_comment: {
exercise_id: exercise_id,
file_id: file_id,
submission_id: submission.id,
question: question
}
}
}
}).done(function() {
hideSpinner();
$.flash.success({ text: $('#askForCommentsButton').data('message-success') })
}).error(ajaxError);
}).done(function() {
hideSpinner();
$.flash.success({ text: $('#askForCommentsButton').data('message-success') });
}).error(ajaxError);
}
createSubmission($('.requestCommentsButton'), null, createRequestForComments);
$('#comment-modal').modal('hide');
var button = $('.requestCommentsButton');
@@ -1207,6 +1279,7 @@ $(function() {
if ($('#editor').isPresent()) {
if (isBrowserSupported()) {
initializeRegexes();
initializeCodePilot();
$('.score, #development-environment').show();
configureEditors();

View File

@@ -151,6 +151,22 @@ $(function() {
});
};
var updateFileTemplates = function(fileType) {
var jqxhr = $.ajax({
url: '/file_templates/by_file_type/' + fileType + '.json',
dataType: 'json'
});
jqxhr.done(function(response) {
var noTemplateLabel = $('#noTemplateLabel').data('text');
var options = "<option value>" + noTemplateLabel + "</option>";
for (var i = 0; i < response.length; i++) {
options += "<option value='" + response[i].id + "'>" + response[i].name + "</option>"
}
$("#code_ocean_file_file_template_id").find('option').remove().end().append($(options));
});
jqxhr.fail(ajaxError);
}
if ($.isController('exercises')) {
if ($('table').isPresent()) {
enableBatchUpdate();
@@ -165,6 +181,10 @@ $(function() {
inferFileAttributes();
observeFileRoleChanges();
overrideTextareaTabBehavior();
} else if ($('#files.jstree').isPresent()) {
var fileTypeSelect = $('#code_ocean_file_file_type_id');
fileTypeSelect.on("change", function() {updateFileTemplates(fileTypeSelect.val())});
updateFileTemplates(fileTypeSelect.val());
}
toggleCodeHeight();
if (window.hljs) {

View File

@@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

View File

@@ -0,0 +1,3 @@
// Place all the styles related to the FileTemplates controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/