jclic 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/README.md +5 -7
  2. package/dist-node/jclic-node.js +14157 -0
  3. package/dist-node/jclic-node.umd.cjs +530 -0
  4. package/package.json +38 -26
  5. package/.vscode/launch.json +0 -33
  6. package/.vscode/settings.json +0 -13
  7. package/CHANGELOG.md +0 -664
  8. package/TRANSLATIONS.md +0 -11
  9. package/build-locales.mjs +0 -82
  10. package/dist/jclic-node.js +0 -31678
  11. package/dist/jclic-node.js.map +0 -1
  12. package/dist/jclic.components.LICENSE +0 -2254
  13. package/dist/jclic.min.js +0 -27
  14. package/dist/jclic.min.js.map +0 -1
  15. package/eslint.config.mjs +0 -31
  16. package/jsdoc.config.js +0 -71
  17. package/locales/ar.po +0 -244
  18. package/locales/ast.po +0 -246
  19. package/locales/bs.po +0 -247
  20. package/locales/ca.po +0 -248
  21. package/locales/ca_ES@valencia.po +0 -248
  22. package/locales/cs.po +0 -244
  23. package/locales/da.po +0 -244
  24. package/locales/de.po +0 -246
  25. package/locales/el.po +0 -244
  26. package/locales/es.po +0 -248
  27. package/locales/eu.po +0 -244
  28. package/locales/fr.po +0 -244
  29. package/locales/gl.po +0 -244
  30. package/locales/he.po +0 -244
  31. package/locales/hr.po +0 -245
  32. package/locales/it.po +0 -246
  33. package/locales/ja.po +0 -242
  34. package/locales/jclic.js.pot +0 -241
  35. package/locales/nb_NO.po +0 -244
  36. package/locales/nl.po +0 -244
  37. package/locales/pl.po +0 -244
  38. package/locales/pt.po +0 -244
  39. package/locales/pt_BR.po +0 -248
  40. package/locales/ro.po +0 -248
  41. package/locales/ru.po +0 -245
  42. package/locales/ta.po +0 -244
  43. package/locales/tr.po +0 -246
  44. package/locales/uk.po +0 -247
  45. package/locales/vec.po +0 -244
  46. package/locales/zh_TW.po +0 -246
  47. package/patches/po2json+1.0.0-beta-3.patch +0 -12
  48. package/src/AWT.js +0 -2067
  49. package/src/Activity.js +0 -1311
  50. package/src/Deps.js +0 -232
  51. package/src/GlobalData.js +0 -5
  52. package/src/JClic.js +0 -196
  53. package/src/JClicPlayer.js +0 -1308
  54. package/src/PlayerHistory.js +0 -305
  55. package/src/Utils.js +0 -1355
  56. package/src/activities/associations/ComplexAssociation.js +0 -321
  57. package/src/activities/associations/SimpleAssociation.js +0 -519
  58. package/src/activities/memory/MemoryGame.js +0 -423
  59. package/src/activities/panels/Explore.js +0 -349
  60. package/src/activities/panels/Identify.js +0 -356
  61. package/src/activities/panels/InformationScreen.js +0 -262
  62. package/src/activities/panels/Menu.js +0 -209
  63. package/src/activities/panels/icons/ico00.png +0 -0
  64. package/src/activities/panels/icons/ico01.png +0 -0
  65. package/src/activities/panels/icons/ico02.png +0 -0
  66. package/src/activities/panels/icons/ico03.png +0 -0
  67. package/src/activities/panels/icons/icofolder.png +0 -0
  68. package/src/activities/puzzles/DoublePuzzle.js +0 -424
  69. package/src/activities/puzzles/ExchangePuzzle.js +0 -374
  70. package/src/activities/puzzles/HolePuzzle.js +0 -360
  71. package/src/activities/text/Complete.js +0 -127
  72. package/src/activities/text/Evaluator.js +0 -534
  73. package/src/activities/text/FillInBlanks.js +0 -426
  74. package/src/activities/text/IdentifyText.js +0 -253
  75. package/src/activities/text/OrderText.js +0 -421
  76. package/src/activities/text/TextActivityBase.js +0 -557
  77. package/src/activities/text/TextActivityDocument.js +0 -658
  78. package/src/activities/text/WrittenAnswer.js +0 -557
  79. package/src/activities/textGrid/CrossWord.js +0 -565
  80. package/src/activities/textGrid/WordSearch.js +0 -458
  81. package/src/activities/textGrid/icons/hIcon.svg +0 -3
  82. package/src/activities/textGrid/icons/vIcon.svg +0 -3
  83. package/src/automation/AutoContentProvider.js +0 -182
  84. package/src/automation/arith/Arith.js +0 -864
  85. package/src/bags/ActivitySequence.js +0 -318
  86. package/src/bags/ActivitySequenceElement.js +0 -161
  87. package/src/bags/ActivitySequenceJump.js +0 -140
  88. package/src/bags/ConditionalJumpInfo.js +0 -113
  89. package/src/bags/JumpInfo.js +0 -136
  90. package/src/bags/MediaBag.js +0 -215
  91. package/src/bags/MediaBagElement.js +0 -516
  92. package/src/boxes/AbstractBox.js +0 -699
  93. package/src/boxes/ActiveBagContent.js +0 -494
  94. package/src/boxes/ActiveBox.js +0 -810
  95. package/src/boxes/ActiveBoxBag.js +0 -357
  96. package/src/boxes/ActiveBoxContent.js +0 -484
  97. package/src/boxes/ActiveBoxGrid.js +0 -179
  98. package/src/boxes/BoxBag.js +0 -500
  99. package/src/boxes/BoxBase.js +0 -398
  100. package/src/boxes/BoxConnector.js +0 -325
  101. package/src/boxes/TextGrid.js +0 -887
  102. package/src/boxes/TextGridContent.js +0 -215
  103. package/src/init-jsdom.js +0 -65
  104. package/src/jclic-node.js +0 -219
  105. package/src/media/ActiveMediaBag.js +0 -145
  106. package/src/media/ActiveMediaPlayer.js +0 -297
  107. package/src/media/AudioBuffer.js +0 -219
  108. package/src/media/EventSounds.js +0 -169
  109. package/src/media/EventSoundsElement.js +0 -155
  110. package/src/media/MediaContent.js +0 -328
  111. package/src/media/MidiAudioPlayer.js +0 -254
  112. package/src/media/icons/audio.svg +0 -3
  113. package/src/media/icons/generic.svg +0 -3
  114. package/src/media/icons/mic.svg +0 -3
  115. package/src/media/icons/movie.svg +0 -3
  116. package/src/media/icons/music.svg +0 -3
  117. package/src/media/icons/url.svg +0 -3
  118. package/src/media/sounds/actionError.mp3 +0 -0
  119. package/src/media/sounds/actionOk.mp3 +0 -0
  120. package/src/media/sounds/click.mp3 +0 -0
  121. package/src/media/sounds/finishedError.mp3 +0 -0
  122. package/src/media/sounds/finishedOk.mp3 +0 -0
  123. package/src/media/sounds/start.mp3 +0 -0
  124. package/src/project/JClicProject.js +0 -282
  125. package/src/project/ProjectSettings.js +0 -273
  126. package/src/report/ActionReg.js +0 -123
  127. package/src/report/ActivityReg.js +0 -271
  128. package/src/report/EncryptMin.js +0 -210
  129. package/src/report/Reporter.js +0 -727
  130. package/src/report/SCORM.js +0 -272
  131. package/src/report/SequenceReg.js +0 -275
  132. package/src/report/SessionReg.js +0 -340
  133. package/src/report/SessionStorageReporter.js +0 -131
  134. package/src/report/TCPReporter.js +0 -628
  135. package/src/shapers/ClassicJigSaw.js +0 -138
  136. package/src/shapers/Holes.js +0 -77
  137. package/src/shapers/JigSaw.js +0 -161
  138. package/src/shapers/Rectangular.js +0 -78
  139. package/src/shapers/Shaper.js +0 -386
  140. package/src/shapers/TriangularJigSaw.js +0 -121
  141. package/src/skins/BlueSkin.js +0 -80
  142. package/src/skins/Counter.js +0 -152
  143. package/src/skins/CustomSkin.js +0 -412
  144. package/src/skins/DefaultSkin.js +0 -376
  145. package/src/skins/EmptySkin.js +0 -82
  146. package/src/skins/GreenSkin.js +0 -94
  147. package/src/skins/MiniSkin.js +0 -130
  148. package/src/skins/OrangeSkin.js +0 -78
  149. package/src/skins/SimpleSkin.js +0 -92
  150. package/src/skins/Skin.js +0 -1021
  151. package/src/skins/assets/actionsIcon.svg +0 -3
  152. package/src/skins/assets/appLogo.svg +0 -8
  153. package/src/skins/assets/basic.css +0 -41
  154. package/src/skins/assets/closeDialogIcon.svg +0 -3
  155. package/src/skins/assets/closeIcon.svg +0 -3
  156. package/src/skins/assets/copyIcon.svg +0 -3
  157. package/src/skins/assets/fullScreenExitIcon.svg +0 -3
  158. package/src/skins/assets/fullScreenIcon.svg +0 -3
  159. package/src/skins/assets/infoIcon.svg +0 -3
  160. package/src/skins/assets/main.css +0 -43
  161. package/src/skins/assets/mainHalf.css +0 -23
  162. package/src/skins/assets/mainTwoThirds.css +0 -23
  163. package/src/skins/assets/mini.css +0 -15
  164. package/src/skins/assets/nextIcon.svg +0 -3
  165. package/src/skins/assets/okDialogIcon.svg +0 -3
  166. package/src/skins/assets/prevIcon.svg +0 -3
  167. package/src/skins/assets/reports.css +0 -156
  168. package/src/skins/assets/reportsIcon.svg +0 -3
  169. package/src/skins/assets/scoreIcon.svg +0 -3
  170. package/src/skins/assets/simple.css +0 -16
  171. package/src/skins/assets/simpleHalf.css +0 -11
  172. package/src/skins/assets/simpleTwoThirds.css +0 -11
  173. package/src/skins/assets/timeIcon.svg +0 -4
  174. package/src/skins/assets/waitAnim.css +0 -54
  175. package/src/skins/assets/waitImgBig.svg +0 -3
  176. package/src/skins/assets/waitImgSmall.svg +0 -3
  177. package/webpack.config.mjs +0 -169
@@ -1,727 +0,0 @@
1
- /**
2
- * File : report/Reporter.js
3
- * Created : 17/05/2016
4
- * By : Francesc Busquets <francesc@gmail.com>
5
- *
6
- * JClic.js
7
- * An HTML5 player of JClic activities
8
- * https://projectestac.github.io/jclic.js
9
- *
10
- * @source https://github.com/projectestac/jclic.js
11
- *
12
- * @license EUPL-1.2
13
- * @licstart
14
- * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)
15
- *
16
- * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by
17
- * the European Commission- subsequent versions of the EUPL (the "Licence");
18
- * You may not use this work except in compliance with the Licence.
19
- *
20
- * You may obtain a copy of the Licence at:
21
- * https://joinup.ec.europa.eu/software/page/eupl
22
- *
23
- * Unless required by applicable law or agreed to in writing, software
24
- * distributed under the Licence is distributed on an "AS IS" basis, WITHOUT
25
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
26
- * Licence for the specific language governing permissions and limitations
27
- * under the Licence.
28
- * @licend
29
- * @module
30
- */
31
-
32
- /* global Promise, window */
33
-
34
- import $ from 'jquery';
35
- import SessionReg from './SessionReg.js';
36
- import Encryption from './EncryptMin.js';
37
- import Scorm from './SCORM.js';
38
- import { log, getMsg, getVal } from '../Utils.js';
39
-
40
- /**
41
- * This class implements the basic operations related with the processing of times and scores
42
- * done by users playing JClic activities. These operations include: identification of users,
43
- * compilation of data coming from the activities, storage of this data for later use, and
44
- * presentation of summarized results.
45
- */
46
- export class Reporter {
47
- /**
48
- * Reporter constructor
49
- * @param {module:JClicPlayer.JClicPlayer} ps - The {@link module:JClicPlayer.JClicPlayer JClicPlayer} used to retrieve localized messages
50
- */
51
- constructor(ps) {
52
- this.ps = ps;
53
- this.sessions = [];
54
- this.started = new Date();
55
- this.initiated = false;
56
- this.info = new ReporterInfo(this);
57
- }
58
-
59
- /**
60
- * Registers a new type of reporter
61
- * @param {string} reporterName - The name used to identify this reporter
62
- * @param {function} reporterClass - The reporter class, usually extending Reporter
63
- * @returns {module:report/Reporter.Reporter} - The provided reporter class
64
- */
65
- static registerClass(reporterName, reporterClass) {
66
- Reporter.CLASSES[reporterName] = reporterClass;
67
- return reporterClass;
68
- }
69
-
70
- /**
71
- * Creates a new Reporter of the requested class
72
- * The resulting object must be prepared to operate with a call to its `init` method.
73
- * @param {string} className - Class name of the requested reporter. When `null`, a basic Reporter is created.
74
- * @param {module:JClicPlayer.JClicPlayer} ps - The {@link module:JClicPlayer.JClicPlayer JClicPlayer} used to retrieve localized messages
75
- * @returns {module:report/Reporter.Reporter}
76
- */
77
- static getReporter(className, ps) {
78
- let result = null;
79
- if (className === null) {
80
- className = 'Reporter';
81
- if (ps.options.hasOwnProperty('reporter'))
82
- className = ps.options.reporter;
83
- }
84
- if (Reporter.CLASSES.hasOwnProperty(className))
85
- result = new Reporter.CLASSES[className](ps);
86
- else
87
- log('error', 'Unknown reporter class: %s', className);
88
-
89
- return result;
90
- }
91
-
92
- /**
93
- * Returns the `info` element associated to this Reporter.
94
- * @returns {module:report/Reporter.ReporterInfo}
95
- */
96
- getInfo() {
97
- return this.info.recalc();
98
- }
99
-
100
- /**
101
- * Gets a specific property from this reporting system
102
- * @param {string} key - Requested property
103
- * @param {string}+ defaultValue - Default return value when requested property does not exist
104
- * @returns {string}
105
- */
106
- getProperty(key, defaultValue) {
107
- return defaultValue;
108
- }
109
-
110
- /**
111
- * Gets a specific boolean property from this reporting system
112
- * @param {string} key - Requested property
113
- * @param {boolean}+ defaultValue - Default return when requested property does not exist
114
- * @returns {boolean}
115
- */
116
- getBooleanProperty(key, defaultValue) {
117
- const s = this.getProperty(key, defaultValue === true ? 'true' : 'false');
118
- return key === null ? defaultValue : s === 'true' ? true : false;
119
- }
120
-
121
- /**
122
- * Gets the list of groups or organizations currently registered in the system. This
123
- * method should be implemented by classes derived of `Reporter`.
124
- * @returns {external:Promise} - When fulfilled, an array of group data is returned as a result
125
- */
126
- getGroups() {
127
- return Promise.reject('No groups defined!');
128
- }
129
-
130
- /**
131
- * Gets the list of users currently registered in the system, optionally filtered by
132
- * a specific group ID. This method should be implemented by classes derived of `Reporter`.
133
- * @param {string}+ groupId - Optional group ID to be used as a filter criteria
134
- * @returns {external:Promise} - When fulfilled, an object with a collection of user data records
135
- * is returned
136
- */
137
- getUsers(groupId) {
138
- return Promise.reject('No users defined in ' + groupId);
139
- }
140
-
141
- /**
142
- * Gets extended data associated with a specific user. This is a method intended to be
143
- * implemented in subclasses.
144
- * @param {string} _userId - The requested user ID
145
- * @returns {external:Promise} - When fulfilled, an object with user data is returned.
146
- */
147
- getUserData(_userId) {
148
- return Promise.reject('Unknown user!');
149
- }
150
-
151
- /**
152
- * Gets extended data associated with a specific group or organization. This
153
- * is a method intended to be implemented in subclasses.
154
- * @param {string} _groupId - The requested group ID
155
- * @returns {external:Promise} - When fulfilled, an object with group data is returned.
156
- */
157
- getGroupData(_groupId) {
158
- return Promise.reject('Unknown group!');
159
- }
160
-
161
- /**
162
- * Checks if this reporting system manages its own database of users and groups. Defaults to `false`
163
- * @returns {boolean}
164
- */
165
- userBased() {
166
- if (this.bUserBased === null)
167
- this.bUserBased = this.getBooleanProperty('USER_TABLES', false);
168
- return this.bUserBased;
169
- }
170
-
171
- /**
172
- * Allows the current user to create a new group, and asks his name
173
- * @returns {external:Promise} - When fulfilled, the chosen name for the new group is returned.
174
- */
175
- promptForNewGroup() {
176
- // TODO: Implement promptForNewGroup
177
- return Promise.reject('Remote creation of groups not yet implemented!');
178
- }
179
-
180
- /**
181
- * Allows the current user to create a new user ID, and asks his ID and password
182
- * @returns {external:Promise} - When fulfilled, an object with the new user ID and password
183
- * is returned.
184
- */
185
- promptForNewUser() {
186
- // TODO: Implement promptForNewUser
187
- return Promise.reject('Remote creation of users not yet implemented!');
188
- }
189
-
190
- /**
191
- * Allows the current user to select its group or organization from the current groups list
192
- * @returns {external:Promise}
193
- */
194
- promptGroupId() {
195
- return new Promise((resolve, reject) => {
196
- if (!this.userBased())
197
- reject('This system does not manage users!');
198
- else {
199
- this.getGroups().then((groupList) => {
200
- // Creation of new groups not yet implemented!
201
- if (!groupList || groupList.length < 1)
202
- reject('No groups defined!');
203
- else {
204
- let sel = 0;
205
- const $groupSelect = $('<select/>').attr({ size: Math.max(3, Math.min(15, groupList.length)) });
206
- groupList.forEach(g => $groupSelect.append($('<option/>').attr({ value: g.id }).text(g.name)));
207
- $groupSelect.change(ev => { sel = ev.target.selectedIndex; });
208
- this.ps.skin.showDlg(true, {
209
- main: [
210
- $('<h2/>', { class: 'subtitle' }).html(getMsg('Select group:')),
211
- $groupSelect],
212
- bottom: [
213
- this.ps.skin.$okDlgBtn,
214
- this.ps.skin.$cancelDlgBtn]
215
- }).then(() => {
216
- resolve(groupList[sel].id);
217
- }).catch(reject);
218
- }
219
- }).catch(reject);
220
- }
221
- });
222
- }
223
-
224
- /**
225
- * Asks for a valid user ID fulfilling the promise if found, rejecting it otherwise
226
- * @param {boolean}+ forcePrompt - Prompt also if `userId` is already defined (default is `false`)
227
- * @returns {external:Promise}
228
- */
229
- promptUserId(forcePrompt) {
230
- return new Promise((resolve, reject) => {
231
- if (this.userId !== null && !forcePrompt)
232
- resolve(this.userId);
233
- else if (!this.userBased())
234
- reject('This system does not manage users!');
235
- else {
236
- const $pwdInput = $('<input/>', { type: 'password', size: 8, maxlength: 64 });
237
- if (this.getBooleanProperty('SHOW_USER_LIST', true)) {
238
- this.promptGroupId().then(groupId => {
239
- this.getUsers(groupId).then(userList => {
240
- // Creation of new users not yet implemented
241
- // let userCreationAllowed = this.getBooleanProperty('ALLOW_CREATE_USERS', false)
242
- if (!userList || userList.length < 1)
243
- reject('Group ' + groupId + ' has no users!');
244
- else {
245
- let sel = -1;
246
- const $userSelect = $('<select/>').attr({ size: Math.max(3, Math.min(15, userList.length)) });
247
- userList.forEach(u => $userSelect.append($('<option/>').attr({ value: u.id }).text(u.name)));
248
- $userSelect.change(ev => { sel = ev.target.selectedIndex; });
249
- this.ps.skin.showDlg(true, {
250
- main: [
251
- $('<h2/>', { class: 'subtitle' }).html(getMsg('Select user:')),
252
- $userSelect,
253
- $('<h2/>', { class: 'subtitle' }).html(getMsg('Password:')).append($pwdInput)],
254
- bottom: [
255
- this.ps.skin.$okDlgBtn,
256
- this.ps.skin.$cancelDlgBtn]
257
- }).then(() => {
258
- if (sel >= 0) {
259
- if (userList[sel].pwd && Encryption.Decrypt(userList[sel].pwd) !== $pwdInput.val()) {
260
- window.alert(getMsg('Incorrect password'));
261
- reject('Incorrect password');
262
- } else {
263
- this.userId = userList[sel].id;
264
- resolve(this.userId);
265
- }
266
- } else
267
- reject('No user has been selected');
268
- }).catch(reject);
269
- }
270
- }).catch(reject);
271
- }).catch(reject);
272
- } else {
273
- const $userInput = $('<input/>', { type: 'text', size: 8, maxlength: 64 });
274
- this.ps.skin.showDlg(true, {
275
- main: [
276
- $('<div/>').css({ 'text-align': 'right' })
277
- .append($('<h2/>', { class: 'subtitle' }).html(getMsg('User:'))
278
- .append($userInput))
279
- .append($('<h2/>', { class: 'subtitle' }).html(getMsg('Password:'))
280
- .append($pwdInput))],
281
- bottom: [
282
- this.ps.skin.$okDlgBtn,
283
- this.ps.skin.$cancelDlgBtn]
284
- }).then(() => {
285
- this.getUserData($userInput.val()).then(user => {
286
- if (user.pwd && Encryption.Decrypt(user.pwd) !== $pwdInput.val()) {
287
- window.alert(getMsg('Incorrect password'));
288
- reject('Incorrect password');
289
- } else {
290
- this.userId = user.id;
291
- resolve(this.userId);
292
- }
293
- }).catch(reject);
294
- }).catch(reject);
295
- }
296
- }
297
- });
298
- }
299
-
300
- /**
301
- * Builds a complex object containing all the results reported while playing activities
302
- * @returns {object} - The current results
303
- */
304
- getData() {
305
-
306
- // Force the re-calculation of all scores
307
- this.info.recalc();
308
-
309
- const result = {
310
- started: this.started.toISOString(),
311
- descriptionKey: this.descriptionKey,
312
- descriptionDetail: this.descriptionDetail,
313
- projects: this.info.numSessions,
314
- sequences: this.info.numSequences,
315
- activitiesDone: this.info.nActivities,
316
- playedOnce: this.info.nActPlayed,
317
- reportable: this.info.reportableActs,
318
- ratioPlayed: Math.round(this.info.ratioPlayed * 100),
319
- activitiesSolved: this.info.nActSolved,
320
- ratioSolved: Math.round(this.info.ratioSolved * 100),
321
- actScore: this.info.nActScore,
322
- partialScore: Math.round(this.info.partialScore * 100),
323
- globalScore: Math.round(this.info.globalScore * 100),
324
- time: Math.round(this.info.tTime / 10) / 100,
325
- actions: this.info.nActions,
326
- sessions: []
327
- };
328
-
329
- if (this.userId)
330
- result.userId = this.userId;
331
- else if (this.SCORM)
332
- result.user = this.SCORM.studentName + (this.SCORM.studentId === '' ? '' : ` (${this.SCORM.studentId})`);
333
-
334
- this.sessions.forEach(sr => {
335
- if (sr.getInfo().numSequences > 0)
336
- result.sessions.push(sr.getData(false, false));
337
- });
338
-
339
- return result;
340
- }
341
-
342
- /**
343
- * Initializes this report system with an optional set of parameters.
344
- * Returns a Promise, fulfilled when the reporter is fully initialized.
345
- * @param {object} [options] - Initial settings passed to the reporting system
346
- * @returns {external:Promise}
347
- */
348
- init(options) {
349
- if (!options)
350
- options = this.ps.options;
351
- this.userId = getVal(options.user);
352
- this.sessionKey = getVal(options.key);
353
- this.sessionContext = getVal(options.context);
354
- this.groupCodeFilter = getVal(options.groupCodeFilter);
355
- this.userCodeFilter = getVal(options.userCodeFilter);
356
- if (options.SCORM !== false) {
357
- this.SCORM = Scorm.getSCORM(this);
358
- if (this.SCORM !== null && this.descriptionKey === Reporter.prototype.descriptionKey)
359
- this.descriptionKey = this.SCORM.getScormType();
360
- }
361
- this.initiated = true;
362
- log('debug', 'Basic Reporter initialized');
363
- return Promise.resolve(true);
364
- }
365
-
366
- /**
367
- * Closes this reporting system
368
- * @returns {external:Promise} - A Promise object to be fullfilled when all pending tasks are finished.
369
- */
370
- end() {
371
- log('debug', 'Basic Reporter ending');
372
- this.endSession();
373
- return Promise.resolve(true);
374
- }
375
-
376
- /**
377
- * Finalizes the current sequence
378
- */
379
- endSequence() {
380
- if (this.currentSession) {
381
- this.currentSession.endSequence();
382
- this.info.valid = false;
383
- }
384
- }
385
-
386
- /**
387
- * Finalizes the current session
388
- */
389
- endSession() {
390
- this.endSequence();
391
- this.currentSession = null;
392
- }
393
-
394
- /**
395
- * Creates a new group (method to be implemented in subclasses)
396
- * @param {object} _gd
397
- */
398
- newGroup(_gd) {
399
- throw "No database!";
400
- }
401
-
402
- /**
403
- * Creates a new user (method to be implemented in subclasses)
404
- * @param {object} _ud
405
- */
406
- newUser(_ud) {
407
- throw "No database!";
408
- }
409
-
410
- /**
411
- * This method should be invoked when a new session starts.
412
- * @param {module:project/JClicProject.JClicProject} jcp - The {@link module:project/JClicProject.JClicProject JClicProject} this session refers to.
413
- */
414
- newSession(jcp) {
415
- this.endSession();
416
- this.currentSession = new SessionReg(jcp);
417
- this.sessions.push(this.currentSession);
418
- this.info.valid = false;
419
- }
420
-
421
- /**
422
- * This method should be invoked when a new sequence starts
423
- * @param {module:bags/ActivitySequenceElement.ActivitySequenceElement} ase - The {@link module:bags/ActivitySequenceElement.ActivitySequenceElement ActivitySequenceElement} referenced by this sequence.
424
- */
425
- newSequence(ase) {
426
- if (this.currentSession) {
427
- this.currentSession.newSequence(ase);
428
- this.info.valid = false;
429
- if (this.SCORM)
430
- this.SCORM.commitInfo();
431
- }
432
- }
433
-
434
- /**
435
- * This method should be invoked when the user starts a new activity
436
- * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} reporter has just started
437
- */
438
- newActivity(act) {
439
- if (this.currentSession) {
440
- this.currentSession.newActivity(act);
441
- this.info.valid = false;
442
- }
443
- }
444
-
445
- /**
446
- * This method should be called when the current activity finishes. Data about user's final results
447
- * on the activity will then be saved.
448
- * @param {number} score - The final score, usually in a 0-100 scale.
449
- * @param {number} numActions - The total number of actions done by the user to solve the activity
450
- * @param {boolean} solved - `true` if the activity was finally solved, `false` otherwise.
451
- */
452
- endActivity(score, numActions, solved) {
453
- if (this.currentSession) {
454
- this.currentSession.endActivity(score, numActions, solved);
455
- this.info.valid = false;
456
- }
457
- }
458
-
459
- /**
460
- * Reports a new action done by the user while playing the current activity
461
- * @param {string} type - Type of action (`click`, `write`, `move`, `select`...)
462
- * @param {string}+ source - Description of the object on which the action is done.
463
- * @param {string}+ dest - Description of the object reporter acts as a target of the action (usually in pairings)
464
- * @param {boolean} ok - `true` if the action was OK, `false`, `null` or `undefined` otherwhise
465
- */
466
- newAction(type, source, dest, ok) {
467
- if (this.currentSession) {
468
- this.currentSession.newAction(type, source, dest, ok);
469
- this.info.valid = false;
470
- }
471
- }
472
-
473
- /**
474
- * Gets information about the current sequence
475
- * @returns {module:report/SequenceReg.SequenceRegInfo}
476
- */
477
- getCurrentSequenceInfo() {
478
- return this.currentSession === null ? null : this.currentSession.getCurrentSequenceInfo();
479
- }
480
-
481
- /**
482
- * Gets the name of the current sequence
483
- * @returns {string}
484
- */
485
- getCurrentSequenceTag() {
486
- return this.currentSession === null ? null : this.currentSession.getCurrentSequenceTag();
487
- }
488
- }
489
-
490
- Object.assign(Reporter.prototype, {
491
- /**
492
- * The {@link module:report/Reporter.ReporterInfo ReporterInfo} used to calculate and store global results.
493
- * @name module:report/Reporter.Reporter#info
494
- * @type {module:report/Reporter.ReporterInfo} */
495
- info: null,
496
- /**
497
- * The {@link module:JClicPlayer.JClicPlayer JClicPlayer} used to retrieve messages
498
- * @name module:report/Reporter.Reporter#ps
499
- * @type {module:JClicPlayer.JClicPlayer} */
500
- ps: null,
501
- /**
502
- * A valid SCORM bridge, or `null` if no SCORM API detected.
503
- * @name module:report/Reporter.Reporter#SCORM */
504
- SCORM: null,
505
- /**
506
- * User ID currently associated with this reporting system
507
- * @name module:report/Reporter.Reporter#userId
508
- * @type {string} */
509
- userId: null,
510
- /**
511
- * Optional key to be added as a field in session records
512
- * @name module:report/Reporter.Reporter#sessionKey
513
- * @type {string} */
514
- sessionKey: null,
515
- /**
516
- * A second optional key to be reported as a field in session records
517
- * @name module:report/Reporter.Reporter#sessionContext
518
- * @type {string} */
519
- sessionContext: null,
520
- /**
521
- * Optional filter key to be used in the group selection dialog
522
- * @name module:report/Reporter.Reporter#groupCodeFilter
523
- * @type {string} */
524
- groupCodeFilter: null,
525
- /**
526
- * Another optional filter key to be used in the user selection dialog
527
- * @name module:report/Reporter.Reporter#userCodeFilter
528
- * @type {string} */
529
- userCodeFilter: null,
530
- /**
531
- * Description of this reporting system
532
- * @name module:report/Reporter.Reporter#descriptionKey
533
- * @type {string} */
534
- descriptionKey: 'Results are not currently being saved',
535
- /**
536
- * Additional info to display after the reporter's `description`
537
- * @name module:report/Reporter.Reporter#descriptionDetail
538
- * @type {string} */
539
- descriptionDetail: '',
540
- /**
541
- * Starting date and time of this report
542
- * @name module:report/Reporter.Reporter#started
543
- * @type {external:Date} */
544
- started: null,
545
- /**
546
- * Array of sessions included in this report
547
- * @name module:report/Reporter.Reporter#sessions
548
- * @type {module:report/SessionReg.SessionReg[]} */
549
- sessions: [],
550
- /**
551
- * Currently active session
552
- * @name module:report/Reporter.Reporter#currentSession
553
- * @type {module:report/SessionReg.SessionReg} */
554
- currentSession: null,
555
- /**
556
- * `true` if the system was successfully initiated, `false` otherwise
557
- * @name module:report/Reporter.Reporter#initiated
558
- * @type {boolean} */
559
- initiated: false,
560
- /**
561
- * `true` if the system is connected to a database with user's data.
562
- * When `false`, a generic ID will be used.
563
- * @name module:report/Reporter.Reporter#bUserBased
564
- * @type {boolean} */
565
- bUserBased: null,
566
- /**
567
- * Maximum number of incorrect UserID attempts
568
- * @name module:report/Reporter.Reporter#MAX_USERID_PROMPT_ATTEMPTS
569
- * @type {number} */
570
- MAX_USERID_PROMPT_ATTEMPTS: 3,
571
- });
572
-
573
- /**
574
- * This object stores the global results of a {@link module:Reporter.Reporter Reporter}
575
- */
576
- export class ReporterInfo {
577
- /**
578
- * ReporterInfo constructor
579
- * @param {module:report/Reporter.Reporter} rep - The {@link module:Reporter.Reporter Reporter} associated tho this `Info` object.
580
- */
581
- constructor(rep) {
582
- this.rep = rep;
583
- }
584
-
585
- /**
586
- * Clears all data associated with this ReporterInfo
587
- */
588
- clear() {
589
- this.numSessions = this.numSequences = this.nActivities = this.reportableActs = this.nActSolved =
590
- this.nActPlayed = this.nActScore = this.nActions = this.ratioSolved = this.ratioPlayed =
591
- this.tScore = this.tTime = this.partialScore = this.globalScore = 0;
592
- this.valid = false;
593
- }
594
-
595
- /**
596
- * Computes the value of all global variables based on the data stored in `sessions`
597
- * @returns {module:report/Reporter.ReporterInfo} - This "info" object
598
- */
599
- recalc() {
600
- if (!this.valid) {
601
- this.clear();
602
- this.rep.sessions.forEach(ses => {
603
- const inf = ses.getInfo();
604
- this.reportableActs += inf.sReg.reportableActs;
605
- if (inf.numSequences > 0) {
606
- this.numSessions++;
607
- this.numSequences += inf.numSequences;
608
- if (inf.nActivities > 0) {
609
- this.nActivities += inf.nActivities;
610
- this.nActPlayed += inf.sReg.actNames.length;
611
- this.nActSolved += inf.nActSolved;
612
- this.nActions += inf.nActions;
613
- if (inf.nActScore > 0) {
614
- this.tScore += inf.tScore * inf.nActScore;
615
- this.nActScore += inf.nActScore;
616
- }
617
- this.tTime += inf.tTime;
618
- }
619
- }
620
- });
621
- if (this.nActivities > 0) {
622
- this.ratioSolved = this.nActSolved / this.nActivities;
623
- if (this.reportableActs > 0)
624
- this.ratioPlayed = this.nActPlayed / this.reportableActs;
625
- this.partialScore = this.tScore / (this.nActScore * 100);
626
- this.globalScore = this.partialScore * this.ratioPlayed;
627
- }
628
- this.valid = true;
629
- }
630
- return this;
631
- }
632
- }
633
-
634
- Object.assign(ReporterInfo.prototype, {
635
- /**
636
- * The Reporter linked to this Info object
637
- * @name module:report/Reporter.ReporterInfo#rep
638
- * @type {module:report/Reporter.Reporter}
639
- */
640
- rep: null,
641
- /**
642
- * When `false`, data must be recalculated
643
- * @name module:report/Reporter.ReporterInfo#valid
644
- * @type {boolean} */
645
- valid: false,
646
- /**
647
- * Number of sessions registered
648
- * @name module:report/Reporter.ReporterInfo#numSessions
649
- * @type {number} */
650
- numSessions: 0,
651
- /**
652
- * Number of sequences played
653
- * @name module:report/Reporter.ReporterInfo#numSequences
654
- * @type {number} */
655
- numSequences: 0,
656
- /**
657
- * Number of activities played
658
- * @name module:report/Reporter.ReporterInfo#nActivities
659
- * @type {number} */
660
- nActivities: 0,
661
- /**
662
- * Number of activities in existing in the played projects suitable to be reported
663
- * @name module:report/Reporter.ReporterInfo#reportableActs
664
- * @type {number} */
665
- reportableActs: 0,
666
- /**
667
- * Number of activities solved
668
- * @name module:report/Reporter.ReporterInfo#nActSolved
669
- * @type {number} */
670
- nActSolved: 0,
671
- /**
672
- * Number of different activities played
673
- * @name module:report/Reporter.ReporterInfo#nActPlayed
674
- * @type {number} */
675
- nActPlayed: 0,
676
- /**
677
- * Global score obtained in all sessions registered by this reporter
678
- * @name module:report/Reporter.ReporterInfo#nActScore
679
- * @type {number} */
680
- nActScore: 0,
681
- /**
682
- * Number of actions done by the user while in this working session
683
- * @name module:report/Reporter.ReporterInfo#nActions
684
- * @type {number} */
685
- nActions: 0,
686
- /**
687
- * Percentage of solved activities
688
- * @name module:report/Reporter.ReporterInfo#ratioSolved
689
- * @type {number} */
690
- ratioSolved: 0,
691
- /**
692
- * Percentage of reportable activities played
693
- * @name module:report/Reporter.ReporterInfo#ratioPlayed
694
- * @type {number} */
695
- ratioPlayed: 0,
696
- /**
697
- * Sum of the scores of all the activities played
698
- * @name module:report/Reporter.ReporterInfo#tScore
699
- * @type {number} */
700
- tScore: 0,
701
- /**
702
- * Global score obtained
703
- * @name module:report/Reporter.ReporterInfo#partialScore
704
- * @type {number} */
705
- partialScore: 0,
706
- /**
707
- * Sum of the playing time reported by each activity (not always equals to the sum of all session's time)
708
- * @name module:report/Reporter.ReporterInfo#tTime
709
- * @type {number} */
710
- tTime: 0,
711
- /**
712
- * Final score based on the percent of reportable activities played. If the user plays all the
713
- * activities, this result equals to `partialScore`.
714
- * @name module:report/Reporter.ReporterInfo#globalScore
715
- * @type {number} */
716
- globalScore: 0,
717
- });
718
-
719
- Reporter.Info = ReporterInfo;
720
-
721
- /**
722
- * Static list of classes derived from Reporter. It should be filled by Reporter classes at declaration time.
723
- * @type {object}
724
- */
725
- Reporter.CLASSES = { 'Reporter': Reporter };
726
-
727
- export default Reporter;