diff --git a/app/assets/javascripts/editor.js.erb b/app/assets/javascripts/editor.js.erb index 87a39fb2..f402e982 100644 --- a/app/assets/javascripts/editor.js.erb +++ b/app/assets/javascripts/editor.js.erb @@ -12,7 +12,9 @@ $(function() { CodeOceanEditorSubmissions, CodeOceanEditorTurtle, CodeOceanEditorWebsocket, - CodeOceanEditorPrompt + CodeOceanEditorPrompt, + CodeOceanEditorCodePilot, + CodeOceanEditorRequestForComments ); if ($('#editor').isPresent() && CodeOceanEditor) { diff --git a/app/assets/javascripts/editor/editor.js.erb b/app/assets/javascripts/editor/editor.js.erb index 94ce0654..7f2672f5 100644 --- a/app/assets/javascripts/editor/editor.js.erb +++ b/app/assets/javascripts/editor/editor.js.erb @@ -1,18 +1,19 @@ var CodeOceanEditor = { + //ACE-Editor-Path ACE_FILES_PATH: '/assets/ace/', + THEME: 'ace/theme/textmate', + + //Color-Encoding for Percentages in Progress Bars (For submissions) ADEQUATE_PERCENTAGE: 50, - ALT_1_KEY_CODE: 161, - ALT_2_KEY_CODE: 8220, - ALT_3_KEY_CODE: 182, - ALT_4_KEY_CODE: 162, + SUCCESSFULL_PERCENTAGE: 90, + + //Key-Codes (for Hotkeys) ALT_R_KEY_CODE: 174, ALT_S_KEY_CODE: 8218, ALT_T_KEY_CODE: 8224, - FILENAME_URL_PLACEHOLDER: '{filename}', - SUCCESSFULL_PERCENTAGE: 90, - THEME: 'ace/theme/textmate', - REMEMBER_TAB: false, - AUTOSAVE_INTERVAL: 15 * 1000, + ENTER_KEY_CODE: 13, + + //Request-For-Comments-Configuration REQUEST_FOR_COMMENTS_DELAY: 3 * 60 * 1000, REQUEST_TOOLTIP_TIME: 5000, @@ -24,19 +25,9 @@ var CodeOceanEditor = { active_file: undefined, active_frame: undefined, running: false, - output_mode_is_streaming: true, - numMessages: 0, lastCopyText: null, - autosaveTimer: null, - autosaveLabel: "#autosave-label span", - - ENTER_KEY_CODE: 13, - - flowrResultHtml: '
', - - configureEditors: function () { _.each(['modePath', 'themePath', 'workerPath'], function (attribute) { ace.config.set(attribute, this.ACE_FILES_PATH); @@ -50,7 +41,6 @@ var CodeOceanEditor = { } }, - confirmReset: function (event) { event.preventDefault(); if (confirm($('#start-over').data('message-confirm'))) { @@ -171,21 +161,6 @@ var CodeOceanEditor = { $('button i.fa-spin').hide(); }, - resetSaveTimer: function () { - clearTimeout(this.autosaveTimer); - this.autosaveTimer = setTimeout(this.autosave.bind(this), this.AUTOSAVE_INTERVAL); - }, - - autosave: function () { - var date = new Date(); - var autosaveLabel = $(this.autosaveLabel); - autosaveLabel.parent().css("visibility", "visible"); - autosaveLabel.text(date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds()); - autosaveLabel.text(date.toLocaleTimeString()); - this.autosaveTimer = null; - this.createSubmission($('#autosave'), null); - }, - 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; @@ -588,10 +563,6 @@ var CodeOceanEditor = { this.renderScore(); this.showFirstFile(); - $(window).on("beforeunload", function() { - if(this.autosaveTimer != null){ - this.autosave(); - } - }.bind(this)); + $(window).on("beforeunload", this.unloadAutoSave.bind(this)); } }; \ No newline at end of file diff --git a/app/assets/javascripts/editor/evaluation.js.erb b/app/assets/javascripts/editor/evaluation.js.erb index 1c457b36..f7b51f30 100644 --- a/app/assets/javascripts/editor/evaluation.js.erb +++ b/app/assets/javascripts/editor/evaluation.js.erb @@ -1,6 +1,19 @@ CodeOceanEditorEvaluation = { chunkBuffer: [{streamedResponse: true}], + /** + * Scoring-Functions + */ + scoreCode: function (event) { + event.preventDefault(); + this.createSubmission('#assess', null, function (response) { + this.showSpinner($('#assess')); + $('#score_div').removeClass('hidden'); + var url = response.score_url; + this.initializeSocketForScoring(url); + }.bind(this)); + }, + handleScoringResponse: function (results) { this.printScoringResults(results); var score = _.reduce(results, function (sum, result) { @@ -10,40 +23,6 @@ CodeOceanEditorEvaluation = { this.renderScore(); }, - handleTestResponse: function (result) { - this.clearOutput(); - this.printOutput(result, false, 0); - if (this.qa_api) { - this.qa_api.executeCommand('syncOutput', [result]); - } - this.showStatus(result); - this.showOutputBar(); - }, - - printOutput: function (output, colorize, index) { - var element = this.findOrCreateOutputElement(index); - if (!colorize) { - if (output.stdout != undefined && output.stdout != '') { - element.append(output.stdout) - } - - 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); - this.flowrOutputBuffer += output.stderr; - this.QaApiOutputBuffer.stderr += output.stderr; - } else if (output.stdout) { - element.addClass('text-success').append(output.stdout); - this.flowrOutputBuffer += output.stdout; - this.QaApiOutputBuffer.stdout += output.stdout; - } else { - element.addClass('text-muted').text($('#output').data('message-no-output')); - } - }, - printScoringResult: function (result, index) { $('#results').show(); var panel = $('#dummies').children().first().clone(); @@ -98,16 +77,22 @@ CodeOceanEditorEvaluation = { this.renderProgressBar(score, maximum_score); }, - scoreCode: function (event) { - event.preventDefault(); - this.createSubmission('#assess', null, function (response) { - this.showSpinner($('#assess')); - $('#score_div').removeClass('hidden'); - var url = response.score_url; - this.initializeSocketForScoring(url); - }.bind(this)); + /** + * Testing-Logic + */ + handleTestResponse: function (result) { + this.clearOutput(); + this.printOutput(result, false, 0); + if (this.qa_api) { + this.qa_api.executeCommand('syncOutput', [result]); + } + this.showStatus(result); + this.showOutputBar(); }, + /** + * Stop-Logic + */ stopCode: function (event) { event.preventDefault(); if (this.isActiveFileStoppable()) { @@ -132,6 +117,9 @@ CodeOceanEditorEvaluation = { this.hidePrompt(); }, + /** + * Output-Logic + */ renderWebsocketOutput: function(msg){ var element = this.findOrCreateRenderElement(0); element.append(msg.data); @@ -149,6 +137,31 @@ CodeOceanEditorEvaluation = { clearOutput: function() { $('#output pre').remove(); + }, + + printOutput: function (output, colorize, index) { + var element = this.findOrCreateOutputElement(index); + if (!colorize) { + if (output.stdout != undefined && output.stdout != '') { + element.append(output.stdout) + } + + 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); + this.flowrOutputBuffer += output.stderr; + this.QaApiOutputBuffer.stderr += output.stderr; + } else if (output.stdout) { + element.addClass('text-success').append(output.stdout); + this.flowrOutputBuffer += output.stdout; + this.QaApiOutputBuffer.stdout += output.stdout; + } else { + element.addClass('text-muted').text($('#output').data('message-no-output')); + } } + }; diff --git a/app/assets/javascripts/editor/flowr.js.erb b/app/assets/javascripts/editor/flowr.js.erb index a4e699f9..4dc0de45 100644 --- a/app/assets/javascripts/editor/flowr.js.erb +++ b/app/assets/javascripts/editor/flowr.js.erb @@ -1,5 +1,6 @@ CodeOceanEditorFlowr = { isFlowrEnabled: true, + flowrResultHtml: '
', handleStderrOutputForFlowr: function () { if (!this.isFlowrEnabled) return; diff --git a/app/assets/javascripts/editor/paiticipantsupport.js.erb b/app/assets/javascripts/editor/paiticipantsupport.js.erb new file mode 100644 index 00000000..1329cef2 --- /dev/null +++ b/app/assets/javascripts/editor/paiticipantsupport.js.erb @@ -0,0 +1,93 @@ +CodeOceanEditorFlowr = { + isFlowrEnabled: true, + flowrResultHtml: '
', + + handleStderrOutputForFlowr: function () { + if (!this.isFlowrEnabled) return; + + var flowrUrl = $('#flowrHint').data('url'); + var flowrHintBody = $('#flowrHint .panel-body'); + var queryParameters = { + query: this.flowrOutputBuffer + }; + + flowrHintBody.empty(); + + jQuery.getJSON(flowrUrl, queryParameters, function (data) { + jQuery.each(data.queryResults, function (index, question) { + var collapsibleTileHtml = this.flowrResultHtml.replace(/{{collapseId}}/g, 'collapse-' + question).replace(/{{headingId}}/g, 'heading-' + question); + var resultTile = $(collapsibleTileHtml); + + resultTile.find('h4 > a').text(question.title + ' | Found via ' + question.source); + resultTile.find('.panel-body').html(question.body); + resultTile.find('.panel-body').append('Open this question'); + + flowrHintBody.append(resultTile); + }); + + if (data.queryResults.length !== 0) { + $('#flowrHint').fadeIn(); + } + }); + + this.flowrOutputBuffer = ''; + } +}; + +CodeOceanEditorCodePilot = { + qa_api: undefined, + QaApiOutputBuffer: {'stdout': '', 'stderr': ''}, + + initializeCodePilot: function () { + if ($('#questions-column').isPresent() && (typeof QaApi != 'undefined') && QaApi.isBrowserSupported()) { + $('#editor-column').addClass('col-md-10').removeClass('col-md-12'); + $('#questions-column').addClass('col-md-2'); + + var node = document.getElementById('questions-holder'); + var url = $('#questions-holder').data('url'); + + this.qa_api = new QaApi(node, url); + } + }, + + handleQaApiOutput: function () { + if (this.qa_api) { + this.qa_api.executeCommand('syncOutput', [[this.QaApiOutputBuffer]]); + // reset the object + } + this.QaApiOutputBuffer = {'stdout': '', 'stderr': ''}; + } +}; + +CodeOceanEditorRequestForComments = { + requestComments: function () { + var user_id = $('#editor').data('user-id'); + var exercise_id = $('#editor').data('exercise-id'); + var file_id = $('.editor').data('id'); + var question = $('#question').val(); + + 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 () { + this.hideSpinner(); + $.flash.success({text: $('#askForCommentsButton').data('message-success')}); + }.bind(this)).error(this.ajaxError.bind(this)); + }; + + this.createSubmission($('.requestCommentsButton'), null, createRequestForComments.bind(this)); + + $('#comment-modal').modal('hide'); + var button = $('#requestComments'); + button.prop('disabled', true); + }, +}; \ No newline at end of file diff --git a/app/assets/javascripts/editor/submissions.js.erb b/app/assets/javascripts/editor/submissions.js.erb index 510b813a..4b8678a7 100644 --- a/app/assets/javascripts/editor/submissions.js.erb +++ b/app/assets/javascripts/editor/submissions.js.erb @@ -1,17 +1,13 @@ - CodeOceanEditorSubmissions = { - collectFiles: function() { - var editable_editors = _.filter(this.editors, function(editor) { - return !editor.getReadOnly(); - }); - return _.map(editable_editors, function(editor) { - return { - content: editor.getValue(), - file_id: $(editor.container).data('file-id') - }; - }); - }, + FILENAME_URL_PLACEHOLDER: '{filename}', + AUTOSAVE_INTERVAL: 15 * 1000, + autosaveTimer: null, + autosaveLabel: "#autosave-label span", + + /** + * Submission-Creation + */ createSubmission: function (initiator, filter, callback) { this.showSpinner(initiator); var jqxhr = this.ajax({ @@ -36,6 +32,18 @@ CodeOceanEditorSubmissions = { jqxhr.fail(this.ajaxError.bind(this)); }, + collectFiles: function() { + var editable_editors = _.filter(this.editors, function(editor) { + return !editor.getReadOnly(); + }); + return _.map(editable_editors, function(editor) { + return { + content: editor.getValue(), + file_id: $(editor.container).data('file-id') + }; + }); + }, + createSubmissionCallback: function(data){ // set all frames context types to submission $('.frame').each(function(index, element) { @@ -69,6 +77,9 @@ CodeOceanEditorSubmissions = { this.toggleButtonStates(); }, + /** + * File-Management + */ destroyFile: function() { this.createSubmission($('#destroy-file'), function(files) { return _.reject(files, function(file) { @@ -125,7 +136,9 @@ CodeOceanEditorSubmissions = { } }, - //Todo Split up in submitpart and run part + /** + * Execution-Logic + */ runCode: function(event) { event.preventDefault(); if ($('#run').is(':visible')) { @@ -172,34 +185,27 @@ CodeOceanEditorSubmissions = { }) }, - requestComments: function () { - var user_id = $('#editor').data('user-id'); - var exercise_id = $('#editor').data('exercise-id'); - var file_id = $('.editor').data('id'); - var question = $('#question').val(); + /** + * Autosave-Logic + */ + resetSaveTimer: function () { + clearTimeout(this.autosaveTimer); + this.autosaveTimer = setTimeout(this.autosave.bind(this), this.AUTOSAVE_INTERVAL); + }, - 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 () { - this.hideSpinner(); - $.flash.success({text: $('#askForCommentsButton').data('message-success')}); - }.bind(this)).error(this.ajaxError.bind(this)); - }; + unloadAutoSave: function() { + if(this.autosaveTimer != null){ + this.autosave(); + } + }, - this.createSubmission($('.requestCommentsButton'), null, createRequestForComments.bind(this)); - - $('#comment-modal').modal('hide'); - var button = $('#requestComments'); - button.prop('disabled', true); + autosave: function () { + var date = new Date(); + var autosaveLabel = $(this.autosaveLabel); + autosaveLabel.parent().css("visibility", "visible"); + autosaveLabel.text(date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds()); + autosaveLabel.text(date.toLocaleTimeString()); + this.autosaveTimer = null; + this.createSubmission($('#autosave'), null); } };