-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathexerciseRecorder.js
197 lines (183 loc) · 6.71 KB
/
exerciseRecorder.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
//
// exerciseRecorder.js
//
// This is the main module of the JSAV Exercise Recorder.
// Submodules of the JSAV Exercise Recorder.
// The program code of these modules will be included in the JSAV Exercise
// Recorder bundle file.
const submission = require('./submission/submission');
const metad_func = require('./metadata/metadata');
const def_func = require('./definitions/definitions');
const init_state_func = require('./initialState/initialState');
const anim_func = require('./animation/animation');
const services = require('./rest-service/services');
const helpers = require('./utils/helperFunctions');
//
// Starter code.
//
// This will be run when the JSAV Exercise Recorder bundle file is referred
// by a <script> tag in a HTML document.
let jsav = {};
let exercise = {};
let exerciseHTML = "";
// Unique address for asynchronously creating a new graded submission.
// This is defined by the A+ LMS. It is used if grading asynchronously.
// https://github.com/apluslms/a-plus/blob/master/doc/GRADERS.md
let submission_url;
// A+ LMS defines: where to post the submission.
// https://github.com/apluslms/a-plus/blob/master/doc/GRADERS.md
let post_url;
const modelAnswer = {
opened: false,
ready: false,
recordingSpeed: 20,
}
Object.seal(modelAnswer);
initialize();
// End of starter code
// Initializer function.
// Binds events of type "jsav-log-event" to function passEvent() (see below).
function initialize() {
setSubmissionAndPostUrl();
submission.reset();
metad_func.setExerciseMetadata(getMetadataFromURLparams())
try {
$(document).off("jsav-log-event");
$(document).on("jsav-log-event", function (event, eventData) {
setTimeout( () => passEvent(eventData), 50);
});
} catch (error) {
console.warn(error)
}
}
// According to https://github.com/apluslms/a-plus/blob/master/doc/GRADERS.md
function setSubmissionAndPostUrl() {
// LMS defines: used if grading asynchronously
submission_url = new URL(location.href).searchParams.get('submission_url');
// LMS defines: where to post the submission
post_url = new URL(location.href).searchParams.get('post_url');
}
// According to https://github.com/apluslms/a-plus/blob/master/doc/GRADERS.md
function getMetadataFromURLparams() {
// set in LMS
const max_points = new URL(location.href).searchParams.get('max_points');
// User identifier
const uid = new URL(location.href).searchParams.get('uid');
// Ordinal number of the submission which has not yet been done
const ordinal_number = new URL(location.href).searchParams.get('ordinal_number');
return { max_points, uid, ordinal_number };
}
// Event handler for JSAV events.
//
// Parameters:
// eventData: { type: string,
// exercise: JSAV exercise, ...}
function passEvent(eventData) {
console.log('EVENT DATA', eventData);
switch(eventData.type){
case 'jsav-init':
// Set exercise title and instructions
def_func.setExerciseOptions(eventData);
break;
case 'jsav-recorded':
// All steps of a JSAV slideshow have been created.
break;
case 'jsav-exercise-init':
// JSAV exercise object created
exercise = eventData.exercise;
jsav = exercise.jsav;
def_func.setDefinitions(exercise);
// init_state_func.fixMissingIds(exercise, passEvent);
// if(init_state_func.someIdMissing(exercise)) {
// init_state_func.fixMissingIds(exercise, passEvent);
// }
init_state_func.setInitialDataStructures(exercise, passEvent);
init_state_func.setAnimationHTML(exercise);
break;
case String(eventData.type.match(/^jsav-array-.*/)):
// JSAV Array data structure events.
// http://jsav.io/datastructures/array/
anim_func.handleArrayEvents(exercise, eventData);
break;
case String(eventData.type.match(/^jsav-node-.*/)):
// JSAV Node data structure events
// http://jsav.io/datastructures/common/
anim_func.handleNodeEvents(exercise, eventData);
break;
case String(eventData.type.match(/^jsav-edge-.*/)):
// JSAV Edge data structure events
// http://jsav.io/datastructures/common/
anim_func.handleEdgeEvents(exercise, eventData);
break;
case 'recorder-set-id':
// This is fired by the initialState.js if the DS ID is set only on first click
init_state_func.setNewId(eventData);
break;
case 'jsav-exercise-undo':
// User clicks the Undo button
setTimeout(() => anim_func.handleGradableStep(exercise, eventData), 100);
break;
case 'jsav-exercise-gradeable-step':
anim_func.handleGradableStep(exercise, eventData);
break;
case 'jsav-exercise-model-open':
// User clicks the Model answer button
modelAnswer.opened = true;
modelAnswer.ready = true;
case 'jsav-exercise-model-init':
if (!modelAnswer.opened) {
exercise.modelav.SPEED = modelAnswer.recordingSpeed + 10;
modelAnswer.ready = !def_func.modelAnswer.recordStep(exercise);
$('.jsavmodelanswer .jsavforward').click();
break;
}
case 'jsav-exercise-model-forward':
// User views the animation of the model answer one step forward
if (!modelAnswer.opened && !modelAnswer.ready) {
setTimeout(() => {
modelAnswer.ready = !def_func.modelAnswer.recordStep(exercise);
$('.jsavmodelanswer .jsavforward').click();
}, modelAnswer.recordingSpeed);
break;
}
case String(eventData.type.match(/^jsav-exercise-model-.*/)):
// All user actions with the model answer animation
if (modelAnswer.opened) {
anim_func.handleModelAnswer(exercise, eventData);
}
break;
case 'jsav-exercise-grade-button':
// User clicks the Grade button
break;
case 'jsav-exercise-grade':
// Automatic grading of the exercise finished
if(!modelAnswer.opened) {
const popUpText = `Recording model answer steps\n ${def_func.modelAnswer.progress()}`;
const popUp = helpers.getPopUp(popUpText);
$('body').append(popUp);
}
finish(eventData);
break;
case 'jsav-exercise-reset':
// User clicks the Reset button
console.warn('Resetting submission');
submission.reset();
break;
default:
console.warn('UNKNOWN EVENT', eventData);
}
}
function finish(eventData) {
if(modelAnswer.ready) {
anim_func.handleGradeButtonClick(eventData);
def_func.setFinalGrade(eventData) && services.sendSubmission(submission.state(), post_url);
submission.reset();
if(!modelAnswer.opened) {
$('#popUpDiv').remove();
}
$(document).off("jsav-log-event");
} else {
$('#popUpContent').text(`Recording model answer steps\n ${def_func.modelAnswer.progress()}`);
setTimeout(() => finish(eventData), modelAnswer.recordingSpeed);
}
}