Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/.idea
18 changes: 18 additions & 0 deletions icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file added index.css
Empty file.
29 changes: 29 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Parsons assessment</title>
<link type="text/css" rel="stylesheet" href="./index.css">
<link type="text/css" rel="stylesheet" href="../assessment-common/assessment.css">
<script type="text/javascript" src="../assessment-common/helper.js"></script>
<script type="text/javascript" src="./index.js"></script>
</head>
<body>
<div class="codio-assessment hide">
<h3 class="codio-assessment-name"></h3>
<div class="codio-assessment-content">
<div class='codio-assessment-instructions'>
<div class='instructions-text'></div>
</div>
</div>
<div class="codio-assessment-guidance-block"></div>
<div class="codio-assessment-footer">
<button class='unblock-button codio-assessment-button'>Modify answer</button>
<button class='check-button codio-assessment-button'></button>
<button class='reset-button codio-assessment-button'>Reset</button>
<button class='diff-button codio-assessment-button'>Diff</button>
</div>
<div class="codio-assessment-results-block"></div>
</div>
</body>
</html>
214 changes: 214 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
(function (){
let assessmentOptions = null
let assessment = null
let processing = false
let showAsDiff = false
let currentData = null

const updateProcessing = (status) => {
processing = status
updateHtml()
}

const applyStateInitial = (data) => {
const {state, result, ...dataWithoutState} = data
assessment = dataWithoutState.assessment
assessmentOptions = dataWithoutState.options

render()
}

const applyState = (data) => {
console.log('assessment iframe applyState', data)
currentData = data
if (!assessment) {
applyStateInitial(data)
return
}
if (data.state) {
updateHtml()
renderGuidance()
return
}
// reset
if (currentData.state && !data.state) {
updateHtml()
renderGuidance()
}
}

const onCheck = (event) => {
event.preventDefault()
updateProcessing(true)

window.codioAssessmentsHelper.send(
window.codioAssessmentsHelper.METHODS.SUBMIT_ANSWER
)
}

const onUnblock = (event) => {
event.preventDefault()
codioAssessmentsHelper.send(window.codioAssessmentsHelper.METHODS.UNBLOCK)
}

const onReset = (event) => {
event.preventDefault()
codioAssessmentsHelper.send(window.codioAssessmentsHelper.METHODS.RESET)
}

const renderContent = () => {
$('.instructions-text').html(assessment.source.settings.instructions)
}

const updateVisibility = (el, visible) => {
visible ? el.removeClass('hide') : el.addClass('hide')
}

const hasDiff = () => {
// todo
}

const updateFooterButtons = () => {
const assessmentState = getAssessmentState()
const {teacherInStudentsProject, showModify, isDisabled, canAnswerAgain, passed, answered} = assessmentState

const checkVisibility = !showModify && assessmentOptions.useSubmitButtons
const checkBtn = $('.check-button')
updateVisibility(checkBtn, checkVisibility)
$('.check-button').attr('disabled', isDisabled)

const unblockVisibility = !teacherInStudentsProject && showModify
updateVisibility($('.unblock-button'), unblockVisibility)

const state = processing ? window.codioAssessmentsHelper.States.PROGRESS : currentData?.result?.state
const resetVisibility = !showModify && answered && assessmentOptions.owner &&
state !== window.codioAssessmentsHelper.States.PROGRESS && !canAnswerAgain
updateVisibility($('.reset-button'), resetVisibility)

const diffBtn = $('.diff-button')
const diffBtnTitle = showAsDiff ? 'Show output' : 'Show diff'
updateVisibility(diffBtn, hasDiff())
diffBtn.html(diffBtnTitle)
}

const renderFooter = () => {
const footerContainer = $('.codio-assessment-footer')
const caption = window.codioAssessmentsHelper.getButtonCaption(assessmentOptions, assessment.source.maxAttemptsCount)
footerContainer.find('.check-button').html(caption)
}

const renderGuidance = () => {
const guidanceBlock = $('.codio-assessment-guidance-block')
guidanceBlock.empty()
const assessmentState = getAssessmentState()
const {result} = currentData || {}
const guidance = window.codioAssessmentsHelper.calculateGuidance(
!assessmentOptions.eduStartedAssignment,
assessmentOptions.showAsTeacher,
assessmentState.answered,
assessment.source,
result ?
{
answerGuidance: result.guidance,
answerPoints: result.points,
attemptsCount: result.usedAttempts,
passed: result.state === window.codioAssessmentsHelper.States.PASS,
isCompletedAndReleased: window.codioAssessmentsHelper.calculateCompletedAndReleased(
assessmentOptions.eduStartedAssignment
)
} : {}
)
if (guidance) {
const guidanceContainer = $('<div class="codio-assessment-guidance-container" />')
const guidanceText = $('<div class="codio-assessment-guidance-text">').html(guidance)
guidanceContainer.append(guidanceText)
guidanceBlock.append(guidanceContainer)
}
}

const renderResult = () => {
// todo render result
}

const getAssessmentState = () => {
const result = currentData ? currentData.result : null
const answered = result?.state && result?.state !== window.codioAssessmentsHelper.States.RESET
const usedAttempts = result?.usedAttempts || 0
const canAnswerAgain = !assessment.source.maxAttemptsCount || usedAttempts < assessment.source.maxAttemptsCount
const showModify = assessmentOptions.showUnblock && (!answered || canAnswerAgain)
const isDisabled = processing ||
assessmentOptions.isDisabled ||
result?.state === window.codioAssessmentsHelper.States.PROGRESS ||
answered && !canAnswerAgain
const teacherInStudentsProject = assessmentOptions.showAsTeacher && !assessmentOptions.owner

return {
isDisabled,
answered,
usedAttempts,
canAnswerAgain,
showModify,
teacherInStudentsProject
}
}

const updateHtml = () => {
if (!assessment) {
return
}
// processing, new state/results
const assessmentState = getAssessmentState()
$('.check-button').attr('disabled', assessmentState.isDisabled)
const blockActionsEl = $('.block-actions')
assessmentState.isDisabled ? blockActionsEl.removeClass('hide') : blockActionsEl.addClass('hide')

updateFooterButtons()
}

const bindEvents = () => {
$('.check-button').on('click', onCheck)
$('.unblock-button').on('click', onUnblock)
$('.reset-button').on('click', onReset)

window.codioAssessmentsHelper.addBodyHeightListener()
}

const render = () => {
const container = $('.codio-assessment')
const nameEl = container.find('.codio-assessment-name')
assessment.source.showName ? nameEl.text(assessment.source.name) : nameEl.remove()
renderContent()
renderFooter()
renderGuidance()
renderResult()
updateHtml()
bindEvents()
container.removeClass('hide')
}

const processMessage = (jsonData) => {
try {
const {method, data} = JSON.parse(jsonData)
console.log('assessment iframe processMessage', jsonData, method, data)
switch (method) {
case window.codioAssessmentsHelper.METHODS.GET_STYLES_RESPONSE:
window.codioAssessmentsHelper.addStyle(data.css)
break
case window.codioAssessmentsHelper.METHODS.GET_STATE_RESPONSE:
updateProcessing(false)
applyState(data)
break
case window.codioAssessmentsHelper.METHODS.CALLBACK: {
window.codioAssessmentsHelper.processCallback(data)
break
}
}
} catch {}
}

window.addEventListener('load', () => {
window.codioAssessmentsHelper.registerMessageListener(processMessage)
window.codioAssessmentsHelper.send(window.codioAssessmentsHelper.METHODS.GET_STATE)
window.codioAssessmentsHelper.send(window.codioAssessmentsHelper.METHODS.GET_STYLES)
})
})()
12 changes: 12 additions & 0 deletions metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "Standard Code Test",
"type": "assessment",
"properties": {
"type": "code-output-compare",
"icon": "./icon.svg",
"defaultHeight": 500,
"gradingControls": {

}
}
}
5 changes: 5 additions & 0 deletions settings.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.settings-commands {
display: flex;
flex-direction: row;
gap: 10px;
}
34 changes: 34 additions & 0 deletions settings.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Settings</title>
<link type="text/css" rel="stylesheet" href="../assessment-common/settings.css">
<link rel="stylesheet" href="./settings.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/cash/8.1.5/cash.min.js"></script>
<script type="text/javascript" src="../assessment-common/helper.js"></script>
<script type="text/javascript" src="./settings.js"></script>
</head>
<body>
<div id="settings-content" class="settings-content">
<div class="settings-row">
<label for="instructions" class="form-label">Instructions</label>
<textarea id="instructions" name="instructions" rows="4" class="form-input"></textarea>
</div>
<div class="settings-commands">
<div class="settings-row">
<label for="command" class="form-label">Command</label>
<input id="command" name="command" class="form-input" type="text"/>
</div>
<div class="settings-row">
<label for="preExecCommand" class="form-label">Pre-Exec Command(Optional)</label>
<input id="preExecCommand" name="preExecCommand" class="form-input"/>
</div>
</div>
<div class="settings-row">
<label for="timeout" class="form-label">Timeout</label>
<input id="timeout" name="timeout" class="form-input" type="number"/>
</div>
</div>
</body>
</html>
44 changes: 44 additions & 0 deletions settings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
(function () {
const collectSettings = () => {
const instructions = $('#instructions').val()
const command = $('#command').val();
const preExecCommand = $('#preExecCommand').val();
const timeout = parseInt($('#timeout').val(), 10);

return {instructions, command, preExecCommand, timeout};
}

const exportSettings = () => {
const data = collectSettings();
window.codioAssessmentsHelper.send(window.codioAssessmentsHelper.METHODS.EXPORT_SETTINGS_RESPONSE, data);
}

const applySettings = (settings = {}) => {
$('#instructions').val(settings.instructions || '');
$('#command').val(settings.command || '');
$('#preExecCommand').val(settings.preExecCommand || '');
$('#timeout').val(settings.timeout || '');
}

const processMessage = (jsonData) => {
console.log('settings iframe processMessage', jsonData)
try {
const {method, data} = JSON.parse(jsonData);
switch (method) {
case window.codioAssessmentsHelper.METHODS.EXPORT_SETTINGS:
exportSettings();
break;
case window.codioAssessmentsHelper.METHODS.GET_SETTINGS_RESPONSE:
applySettings(data.settings);
break;
}
} catch {}
}

const onLoad = async () => {
window.codioAssessmentsHelper.registerMessageListener(processMessage)
window.codioAssessmentsHelper.send(window.codioAssessmentsHelper.METHODS.GET_SETTINGS)
}

window.addEventListener('load', onLoad);
})()