Difference between revisions of "Widget:CodeExplorer"
From Coder Merlin
Line 46: | Line 46: | ||
<textarea id="codeEditorTextArea<!--{$exerciseID|validate:int}-->"><!--{$initialCode}--></textarea> | <textarea id="codeEditorTextArea<!--{$exerciseID|validate:int}-->"><!--{$initialCode}--></textarea> | ||
<script> | <script> | ||
function markupWarningsAndErrorsHTML(string) { | |||
let html = ""; | |||
if (typeof string == "string") { | |||
let lines = string.split("<br/>"); | |||
for (const line of lines) { | |||
let decoration = "merlin-code-explorer-combined-output-default"; | |||
if (line.match(/warning:/)) { | |||
decoration = "merlin-code-explorer-combined-output-warning"; | |||
} | |||
if (line.match(/error:/)) { | |||
decoration = "merlin-code-explorer-combined-output-error"; | |||
} | |||
html += "<span class='" + decoration + "'>" + line + "</span><br/>"; | |||
} | |||
} | |||
return html; | |||
} | |||
let codeEditor<!--{$exerciseID|validate:int}-->; | |||
window.addEventListener('load', (event) => { | window.addEventListener('load', (event) => { | ||
codeEditor<!--{$exerciseID|validate:int}--> = CodeMirror.fromTextArea(document.getElementById('codeEditorTextArea<!--{$exerciseID|validate:int}-->'), | codeEditor<!--{$exerciseID|validate:int}--> = CodeMirror.fromTextArea(document.getElementById('codeEditorTextArea<!--{$exerciseID|validate:int}-->'), | ||
Line 78: | Line 96: | ||
// Disable buttons | // Disable buttons | ||
let executeButton = $("#codeEditorExecuteButton<!--{$exerciseID|validate:int}-->"); | |||
let submitButton = $("#codeEditorSubmitButton<!--{$exerciseID|validate:int}-->"); | |||
let executeButtonBackgroundColor = executeButton.css("background-color"); | |||
let submitButtonBackgroundColor = submitButton.css("background-color"); | |||
executeButton.attr("disabled", true); | executeButton.attr("disabled", true); | ||
executeButton.css("background-color", "gray"); | executeButton.css("background-color", "gray"); | ||
Line 88: | Line 106: | ||
// Clear output | // Clear output | ||
$("# | $("#codeEditorCompilerOutput<!--{$exerciseID|validate:int}-->").empty(); | ||
$("#codeEditorExecutionOutput<!--{$exerciseID|validate:int}-->").empty(); | |||
// Submit form via POST | // Submit form via POST | ||
let username = "<!--{$userName}-->".toLowerCase(); | |||
let sessionID = "<!--{$sessionID}-->" | |||
let url = (subdomain() == "stg") ? | |||
"https://language-server-stg.codermerlin.com/" : | "https://language-server-stg.codermerlin.com/" : | ||
"https://language-server.codermerlin.com/"; | "https://language-server.codermerlin.com/"; | ||
Line 104: | Line 123: | ||
break; | break; | ||
} | } | ||
let requestObject = { | |||
"sourceLanguage": {"swift": {}}, | |||
"sourceFiles": [{"path": "main.swift", "contents": codeEditor<!--{$exerciseID|validate:int}-->.getValue()}], | |||
"executionMode": {"compileAndExecute": {}} | |||
}; | |||
let requestString = JSON.stringify(requestObject); | |||
let response = $.ajax({ | |||
type: "POST", | type: "POST", | ||
url, | url, | ||
Line 113: | Line 138: | ||
"sessionID": sessionID | "sessionID": sessionID | ||
}, | }, | ||
data: | data: requestString, | ||
dataType: "json", | |||
contentType : "application/json", | |||
timeout: 6000, | |||
error: function(jqXHR, textStatus, errorThrown) { | |||
// Display error | // Display error | ||
$("# | $("#codeEditorCompilerOutput<!--{$exerciseID|validate:int}-->").append("<span class='merlin-code-explorer-combined-output-error'>" + | ||
" | "Internal error: " + textStatus + "<br/>" + errorThrown + "<br/>" + | ||
"</span><br/>"); | "</span><br/>"); | ||
// Re-enable buttons | // Re-enable buttons | ||
executeButton.attr("disabled", false); | executeButton.attr("disabled", false); | ||
Line 135: | Line 159: | ||
// Collect response data | // Collect response data | ||
response.done(function( | response.done(function(responseObject) { | ||
switch (event.target.submitter) { | |||
case "execute": | |||
let compilationStatus = responseObject.compilationStatus; | |||
let compilationOutput = compilationStatus.standardOutput; | |||
let compilationError = compilationStatus.standardError; | |||
if (compilationStatus.timedOut) { | |||
compilationError += "error: timed out\n"; | |||
} | |||
$("#codeEditorCompilerOutput<!--{$exerciseID|validate:int}-->"). | |||
append(markupWarningsAndErrorsHTML(consoleToHTML(compilationError))); | |||
$("#codeEditorCompilerOutput<!--{$exerciseID|validate:int}-->"). | |||
append(markupWarningsAndErrorsHTML(consoleToHTML(compilationOutput))); | |||
let executionStatus = responseObject.executionStatus; | |||
let executionOutput = (typeof executionStatus == "object") ? executionStatus.standardOutput : ""; | |||
let executionError = (typeof executionStatus == "object") ? executionStatus.standardError : ""; | |||
if (typeof executionStatus == "object" && executionStatus.timedOut) { | |||
executionError += "error: timed out\n"; | |||
} | |||
$("#codeEditorExecutionOutput<!--{$exerciseID|validate:int}-->").append(consoleToHTML(executionError)); | |||
$("#codeEditorExecutionOutput<!--{$exerciseID|validate:int}-->").append(consoleToHTML(executionOutput)); | |||
break; | |||
case "submit": | |||
let standardOutput = responseObject.standardOutput; | |||
$("#codeEditorExecutionOutput<!--{$exerciseID|validate:int}-->").append(consoleToHTML(standardOutput)); | |||
break; | |||
} | |||
// Re-enable buttons | // Re-enable buttons | ||
executeButton.attr("disabled", false); | executeButton.attr("disabled", false); | ||
Line 175: | Line 205: | ||
<input id="codeEditorSubmitButton<!--{$exerciseID|validate:int}-->" class="merlin-code-explorer-submit-button" onclick="this.form.submitter = 'submit';" type="submit" value="Submit"/> | <input id="codeEditorSubmitButton<!--{$exerciseID|validate:int}-->" class="merlin-code-explorer-submit-button" onclick="this.form.submitter = 'submit';" type="submit" value="Submit"/> | ||
</div> | </div> | ||
<div id=" | <div id="codeEditorCompilerOutput<!--{$exerciseID|validate:int}-->" class="merlin-code-explorer-combined-output"></div> | ||
<div id="codeEditorExecutionOutput<!--{$exerciseID|validate:int}-->" class="merlin-code-explorer-combined-output"></div> | |||
</div> | </div> | ||
</form> | </form> | ||
</includeonly> | </includeonly> |
Revision as of 15:48, 30 December 2022
Parameters:
- userName
- string: The current user's username
- sessionID
- string: The ID of the current user's session
- experienceID
- string: The experienceID of the page from which the widget is invoked
- codeExplorerGroupID
- string: The code explorer group. If empty, the submit button will be disabled.
- exerciseID
- integer: exercise id for editor, must be unique per page
- width
- integer|string: percentage (as string, e.g. "100%" or integer size in pixels), null for no change (full width)
- height
- integer|string: percentage (as string, e.g. "100%" or integer size in pixels), null for no change (~10 lines)
- lineNumbers
- boolean: true to display line numbers
- theme
- string: name of theme (which must be loaded via css)
- readOnly
- boolean: true if editing should be disabled
- mode
- string: language for highlighting (which must be loaded via js)
- initialCode
- string: initial code to place in editor
Example:
{{#widget:CodeExplorer |userName=john-williams |sessionID=qh0ubrrme911kcg7db0i0ec6lct94h7f |experienceID=W1020.23 |codeExplorerGroupID=WTRS-8527 |exerciseID=10 |width=null |height=null |lineNumbers=true |theme=vibrant-ink |readOnly=false |mode=swift |initialCode=func sayHello() { print("Hello, World!") } }}