Difference between revisions of "Widget:CodeExplorer"
From Coder Merlin
Line 5: | Line 5: | ||
;experienceID: string: The experienceID of the page from which the widget is invoked | ;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. | ;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) | ;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) | ;height: integer|string: percentage (as string, e.g. "100%" or integer size in pixels), null for no change (~10 lines) | ||
Line 21: | Line 21: | ||
|experienceID=W1020.23 | |experienceID=W1020.23 | ||
|codeExplorerGroupID=WTRS-8527 | |codeExplorerGroupID=WTRS-8527 | ||
| | |exerciseID=10 | ||
|width=null | |width=null | ||
|height=null | |height=null | ||
Line 36: | Line 36: | ||
<includeonly> | <includeonly> | ||
<form action="" id="codeEditorForm<!--{$ | <form action="" id="codeEditorForm<!--{$exerciseID|validate:int}-->"> | ||
<div class="merlin-code-explorer-container"> | <div class="merlin-code-explorer-container"> | ||
<div class="merlin-code-explorer-banner"> | <div class="merlin-code-explorer-banner"> | ||
Line 44: | Line 44: | ||
</div> | </div> | ||
<div class="merlin-code-explorer-code-panel"> | <div class="merlin-code-explorer-code-panel"> | ||
<textarea id="codeEditorTextArea<!--{$ | <textarea id="codeEditorTextArea<!--{$exerciseID|validate:int}-->"><!--{$initialCode}--></textarea> | ||
<script> | <script> | ||
var codeEditor<!--{$ | var codeEditor<!--{$exerciseID|validate:int}-->; | ||
window.addEventListener('load', (event) => { | window.addEventListener('load', (event) => { | ||
codeEditor<!--{$ | codeEditor<!--{$exerciseID|validate:int}--> = CodeMirror.fromTextArea(document.getElementById('codeEditorTextArea<!--{$exerciseID|validate:int}-->'), | ||
{ | { | ||
keyMap: "emacs", | keyMap: "emacs", | ||
Line 58: | Line 58: | ||
); | ); | ||
// Set size | // Set size | ||
codeEditor<!--{$ | codeEditor<!--{$exerciseID|validate:int}-->.setSize("<!--{$width}-->", "<!--{$height}-->"); | ||
// Determine if submit button is enabled, if not, disable | // Determine if submit button is enabled, if not, disable | ||
var isSubmitEnabled = '<!--{$codeExplorerGroupID|strip}-->'.length > 0; | var isSubmitEnabled = '<!--{$codeExplorerGroupID|strip}-->'.length > 0; | ||
if (isSubmitEnabled) { | if (isSubmitEnabled) { | ||
var submitButton = $("#codeEditorSubmitButton<!--{$ | var submitButton = $("#codeEditorSubmitButton<!--{$exerciseID|validate:int}-->"); | ||
submitButton.prop("value", "Submit to <!--{$codeExplorerGroupID|strip}-->"); | submitButton.prop("value", "Submit to <!--{$codeExplorerGroupID|strip}-->"); | ||
} else { | } else { | ||
var submitButton = $("#codeEditorSubmitButton<!--{$ | var submitButton = $("#codeEditorSubmitButton<!--{$exerciseID|validate:int}-->"); | ||
submitButton.attr("disabled", true); | submitButton.attr("disabled", true); | ||
submitButton.css("background-color", "gray"); | submitButton.css("background-color", "gray"); | ||
Line 72: | Line 72: | ||
// Attach handler to form | // Attach handler to form | ||
$("#codeEditorForm<!--{$ | $("#codeEditorForm<!--{$exerciseID|validate:int}-->").submit(function(event) { | ||
// Suppress standard submission | // Suppress standard submission | ||
Line 78: | Line 78: | ||
// Disable buttons | // Disable buttons | ||
var executeButton = $("#codeEditorExecuteButton<!--{$ | var executeButton = $("#codeEditorExecuteButton<!--{$exerciseID|validate:int}-->"); | ||
var submitButton = $("#codeEditorSubmitButton<!--{$ | var submitButton = $("#codeEditorSubmitButton<!--{$exerciseID|validate:int}-->"); | ||
var executeButtonBackgroundColor = executeButton.css("background-color"); | var executeButtonBackgroundColor = executeButton.css("background-color"); | ||
var submitButtonBackgroundColor = submitButton.css("background-color"); | var submitButtonBackgroundColor = submitButton.css("background-color"); | ||
Line 88: | Line 88: | ||
// Clear output | // Clear output | ||
$("#codeEditorCombinedOutput<!--{$ | $("#codeEditorCombinedOutput<!--{$exerciseID|validate:int}-->").empty(); | ||
// Submit form via POST | // Submit form via POST | ||
var username = "<!--{$userName}-->".toLowerCase(); | |||
var sessionID = "<!--{$sessionID}-->" | |||
var url = (subdomain() == "stg") ? | var url = (subdomain() == "stg") ? | ||
"https://language-server-stg.codermerlin.com/" : | "https://language-server-stg.codermerlin.com/" : | ||
Line 96: | Line 98: | ||
switch (event.target.submitter) { | switch (event.target.submitter) { | ||
case "execute": | case "execute": | ||
url += " | url += "experiences/" + "<!--{$experienceID}-->/" + "exercises/" + "<!--{$exerciseID}-->" + "/executions"; | ||
break; | break; | ||
case "submit": | case "submit": | ||
url += " | url += "codeExplorerGroups/" + "<!--{$codeExplorerGroupID}-->/" + "experiences/" + "<!--{$experienceID}-->/" + "exercises/" + "<!--{$exerciseID}-->"; | ||
break; | break; | ||
} | } | ||
console.log(url); | console.log(url); | ||
var response = $. | var response = $.ajax({ | ||
type: "POST", | |||
url, | |||
"sourceCodeLanguage": "swift", | headers: { | ||
"username": username, | |||
"sessionID": sessionID | |||
}, | |||
data: { | |||
"sourceCodeLanguage": "swift", | |||
"sourceCode": codeEditor<!--{$exerciseID|validate:int}-->.getValue() | |||
}, | |||
timeout: 6000, | |||
error: function(jqXHR, textStatus, errorThrown) { | |||
// Display error | |||
$("#codeEditorCombinedOutput<!--{$exerciseID|validate:int}-->").append("<span class='merlin-code-explorer-combined-output-error'>" + | |||
"Failed to complete operation." + | |||
"</span><br/>"); | |||
console.log(textStatus + " " + errorThrown); | |||
// Re-enable buttons | |||
executeButton.attr("disabled", false); | |||
executeButton.css("background-color", executeButtonBackgroundColor); | |||
if (isSubmitEnabled) { | |||
submitButton.attr("disabled", false); | |||
submitButton.css("background-color", submitButtonBackgroundColor); | |||
} | |||
} | |||
}); | }); | ||
// Collect response data | // Collect response data | ||
response.done(function(data) { | response.done(function(data) { | ||
var executionCodeResponse = | var executionCodeResponse = JSON.parse(data); | ||
var standardError = consoleToHTML(executionCodeResponse.standardError); | var standardError = consoleToHTML(executionCodeResponse.standardError); | ||
var standardOutput = consoleToHTML(executionCodeResponse.standardOutput); | var standardOutput = consoleToHTML(executionCodeResponse.standardOutput); | ||
Line 132: | Line 155: | ||
errorClass = "merlin-code-explorer-combined-output-error"; | errorClass = "merlin-code-explorer-combined-output-error"; | ||
}; | }; | ||
$("#codeEditorCombinedOutput<!--{$ | $("#codeEditorCombinedOutput<!--{$exerciseID|validate:int}-->").append("<span class='" + errorClass + "'>" + errorLine + "</span><br/>"); | ||
}; | }; | ||
$("#codeEditorCombinedOutput<!--{$ | $("#codeEditorCombinedOutput<!--{$exerciseID|validate:int}-->").append(standardOutput); | ||
// Re-enable buttons | // Re-enable buttons | ||
Line 149: | Line 172: | ||
</div> | </div> | ||
<div class="merlin-code-explorer-control-panel"> | <div class="merlin-code-explorer-control-panel"> | ||
<input id="codeEditorExecuteButton<!--{$ | <input id="codeEditorExecuteButton<!--{$exerciseID|validate:int}-->" class="merlin-code-explorer-execute-button" onclick="this.form.submitter = 'execute';" type="submit" value="Run" /> | ||
<input id="codeEditorSubmitButton<!--{$ | <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="codeEditorCombinedOutput<!--{$ | <div id="codeEditorCombinedOutput<!--{$exerciseID|validate:int}-->" class="merlin-code-explorer-combined-output"></div> | ||
</div> | </div> | ||
</form> | </form> | ||
</includeonly> | </includeonly> |
Revision as of 05:52, 5 October 2021
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!") } }}