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
13 changes: 13 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.
5 changes: 5 additions & 0 deletions index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.codio-assessment-splice-iframe {
height: auto;
width: 100%;
max-width: 100%;
}
23 changes: 23 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>SPLICE assessment</title>
<script src="//cdnjs.cloudflare.com/ajax/libs/cash/8.1.5/cash.min.js"></script>
<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>
</head>
<body>
<div class="codio-assessment codio-assessment-splice 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-iframe-wrapper"></div>
</div>
<script defer type="text/javascript" src="./index.js"></script>
</body>
</html>
187 changes: 187 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
(function (){
let assessmentOptions = null
let assessment = null
let processing = false
let currentData = null

const SPLICE_METHODS = {
REPORT_SCORE_AND_STATE: 'SPLICE.reportScoreAndState',
GET_STATE: 'SPLICE.getState',
GET_STATE_RESPONSE: 'SPLICE.getState.response',
FRAME_RESIZE: 'lti.frameResize',
}

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

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)
}
// todo sent set state to iframe??
}

const renderContent = () => {
$('.instructions-text').html(assessment.source.settings.instructions)
const iframe = $(`<iframe class="codio-assessment-splice-iframe" />`)
iframe.attr('title', `Assessment - ${assessment.source.name}`)
iframe.attr('src', assessment.source.settings.url)
$('.codio-assessment-iframe-wrapper').append(iframe)
}

const bindEvents = () => {
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()
bindEvents()
container.removeClass('hide')
}

const sendToIframe = (method, message) => {
const iframe = $('.codio-assessment-splice-iframe')
iframe[0].contentWindow.postMessage({subject: method, ...message}, '*')
}

const getStateObj = () => {
const {result} = currentData || {}
if (!result?.stateJson) {
return null
}

try {
return JSON.parse(result.stateJson)
} catch {
return null
}
}

const sendStateToIframe = (messageId) => {
if (!messageId) {
return
}

sendToIframe(
SPLICE_METHODS.GET_STATE_RESPONSE, {
message_id: messageId,
state: getStateObj()
}
)
}

const reportScoreAndState = ({score, state}) => {
if (processing) {
return
}
updateProcessing(true)
window.codioAssessmentsHelper.send(
window.codioAssessmentsHelper.METHODS.SUBMIT_ANSWER,
{result: {score, state}}
)
}

const resizeIframe = ({width, height}) => {
const iframe = $('.codio-assessment-splice-iframe')
iframe.width(width || '100%').height(height || 'auto')
}

const sendGetFileContent = async (data) => {
const messageId = data.message_id || window.codioAssessmentsHelper.GUID()
try {
const result = await window.codioAssessmentsHelper.sendAndWait(
window.codioAssessmentsHelper.METHODS.GET_FILE_CONTENT, data
)
sendToIframe(
window.codioAssessmentsHelper.METHODS.CODIO_GET_FILE_CONTENT_RESPONSE,
{message_id: messageId, content: result.content}
)
} catch (err) {
sendToIframe(
window.codioAssessmentsHelper.METHODS.CODIO_GET_FILE_CONTENT_RESPONSE,
{message_id: messageId, error: err.message}
)
}
}

const sendSetFileContent = async (data) => {
const messageId = data.message_id || window.codioAssessmentsHelper.GUID()
try {
await window.codioAssessmentsHelper.sendAndWait(
window.codioAssessmentsHelper.METHODS.SET_FILE_CONTENT, data
)
sendToIframe(
window.codioAssessmentsHelper.METHODS.CODIO_SET_FILE_CONTENT_RESPONSE,
{message_id: messageId}
)
} catch (err) {
sendToIframe(
window.codioAssessmentsHelper.METHODS.CODIO_SET_FILE_CONTENT_RESPONSE,
{message_id: messageId, error: err.message}
)
}
}

const getSpliceData = (data) => {
if (!data?.subject) {
return null
}
const {subject, ...rest} = data
return {method: subject, data: {...rest}}
}

const processMessage = (jsonData) => {
try {
const {method, data} = getSpliceData(jsonData) || 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
}
case SPLICE_METHODS.GET_STATE:
sendStateToIframe(data.message_id)
break
case SPLICE_METHODS.REPORT_SCORE_AND_STATE:
reportScoreAndState(data)
break
case SPLICE_METHODS.FRAME_RESIZE:
resizeIframe(data)
break
case window.codioAssessmentsHelper.METHODS.CODIO_GET_FILE_CONTENT:
sendGetFileContent(data)
break
case window.codioAssessmentsHelper.METHODS.CODIO_SET_FILE_CONTENT:
sendSetFileContent(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": "Splice",
"type": "assessment",
"properties": {
"type": "splice",
"icon": "./icon.svg",
"gradingControls": {
"points": true,
"useMaximumScore": true
}
}
}
Empty file added settings.css
Empty file.
24 changes: 24 additions & 0 deletions settings.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!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="codio-assessment-settings-content">
<div class="codio-assessment-settings-form-control codio-assessment-settings-form-input-container">
<label for="instructions" class="codio-assessment-settings-form-label">Instructions</label>
<textarea id="instructions" name="instructions" rows="4" class="codio-assessment-settings-form-input"></textarea>
</div>
<div class="codio-assessment-settings-form-control codio-assessment-settings-form-input-container">
<label for="url" class="codio-assessment-settings-form-label">Assessment Url</label>
<input id="url" name="url" class="codio-assessment-settings-form-input" type="text"/>
</div>
</div>
</body>
</html>
39 changes: 39 additions & 0 deletions settings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
(function () {
const collectSettings = () => {
const instructions = $('#instructions').val()
const url = $('#url').val()
return {instructions, url};
}

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

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

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);
})()