@liascript/exporter 3.0.0--1.0.3 → 3.0.1--1.0.3

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 (72) hide show
  1. package/dist/assets/capacitor/{index.bfe7363b.js → index.a7f021f7.js} +1 -1
  2. package/dist/assets/capacitor/index.html +1 -1
  3. package/dist/assets/capacitor/{jszip.min.f6eda75b.js → jszip.min.43389eb1.js} +1 -1
  4. package/dist/assets/capacitor/{trystero-ipfs.min.b27a61d7.js → trystero-ipfs.min.f25fe3e7.js} +1 -1
  5. package/dist/assets/indexeddb/{index.599a57d6.js → index.4aceca2f.js} +1 -1
  6. package/dist/assets/indexeddb/index.html +1 -1
  7. package/dist/assets/indexeddb/{jszip.min.63142cc8.js → jszip.min.4fbcc13f.js} +1 -1
  8. package/dist/assets/scorm2004/{index.7a5820ab.js → index.33bec53a.js} +1 -1
  9. package/dist/assets/scorm2004/index.html +1 -1
  10. package/dist/assets/scorm2004/{jszip.min.63142cc8.js → jszip.min.4fbcc13f.js} +1 -1
  11. package/dist/assets/xapi/{index.018a032a.js → index.f2e89e49.js} +1 -1
  12. package/dist/assets/xapi/index.html +1 -1
  13. package/dist/assets/xapi/{jszip.min.eaecf580.js → jszip.min.19c66d77.js} +1 -1
  14. package/dist/index.js +47 -47
  15. package/dist/server/presets.json +94 -0
  16. package/dist/server/presets.yaml +120 -0
  17. package/dist/server/public/app.js +1 -0
  18. package/dist/server/public/assets/android.svg +38 -0
  19. package/dist/server/public/assets/cmi.svg +154 -0
  20. package/dist/server/public/assets/docx.svg +20 -0
  21. package/dist/server/public/assets/edX.svg +75 -0
  22. package/dist/server/public/assets/edx.svg +75 -0
  23. package/dist/server/public/assets/epub.svg +18 -0
  24. package/dist/server/public/assets/icon.svg +82 -0
  25. package/dist/server/public/assets/ilias.png +0 -0
  26. package/dist/server/public/assets/json.svg +4 -0
  27. package/dist/server/public/assets/learnworlds.png +0 -0
  28. package/dist/server/public/assets/moodle.svg +190 -0
  29. package/dist/server/public/assets/opal.png +0 -0
  30. package/dist/server/public/assets/openolat.png +0 -0
  31. package/dist/server/public/assets/pdf.svg +4 -0
  32. package/dist/server/public/assets/rdf.svg +4 -0
  33. package/dist/server/public/assets/scorm.png +0 -0
  34. package/dist/server/public/assets/web.png +0 -0
  35. package/dist/server/public/assets/xapi.png +0 -0
  36. package/dist/server/public/i18n.js +1 -0
  37. package/dist/server/public/index.html +1587 -0
  38. package/dist/server/public/locales/de.json +247 -0
  39. package/dist/server/public/locales/en.json +247 -0
  40. package/dist/server/public/status.html +251 -0
  41. package/dist/server/public/styles.css +712 -0
  42. package/package.json +5 -1
  43. package/.parcelrc +0 -3
  44. package/DESKTOP_APP_README.md +0 -58
  45. package/DOCKERHUB_DESCRIPTION.md +0 -52
  46. package/Dockerfile +0 -129
  47. package/PLAYSTORE_GUIDE.md +0 -172
  48. package/action.yml +0 -157
  49. package/custom.css +0 -10
  50. package/electron-builder.json +0 -149
  51. package/src/cli.ts +0 -69
  52. package/src/colorize.ts +0 -115
  53. package/src/export/android.ts +0 -419
  54. package/src/export/docx.ts +0 -1025
  55. package/src/export/epub.ts +0 -1306
  56. package/src/export/h5p.ts +0 -390
  57. package/src/export/helper.ts +0 -360
  58. package/src/export/ims.ts +0 -191
  59. package/src/export/pdf.ts +0 -406
  60. package/src/export/presets.ts +0 -220
  61. package/src/export/project.ts +0 -829
  62. package/src/export/rdf.ts +0 -551
  63. package/src/export/scorm12.ts +0 -167
  64. package/src/export/scorm2004.ts +0 -140
  65. package/src/export/web.ts +0 -306
  66. package/src/export/xapi.ts +0 -424
  67. package/src/exporter.ts +0 -296
  68. package/src/index.ts +0 -96
  69. package/src/parser.ts +0 -373
  70. package/src/presets.yaml +0 -219
  71. package/src/types.ts +0 -82
  72. package/tsconfig.json +0 -24
@@ -1,424 +0,0 @@
1
- import * as helper from './helper'
2
- import * as RDF from './rdf'
3
- import * as COLOR from '../colorize'
4
-
5
- const path = require('path')
6
- const fs = require('fs-extra')
7
-
8
- /**
9
- * Help function for xAPI export
10
- */
11
- export function help() {
12
- console.log('')
13
- console.log(COLOR.heading('xAPI settings:'), '\n')
14
-
15
- COLOR.info(
16
- 'xAPI (Experience API) is a standard for tracking learning experiences and interactions.',
17
- )
18
-
19
- console.log('\nLearn more: https://xapi.com/\n')
20
-
21
- COLOR.command(
22
- null,
23
- '--xapi-endpoint',
24
- ' URL of the Learning Record Store (LRS) endpoint',
25
- )
26
- COLOR.command(
27
- null,
28
- '--xapi-auth',
29
- ' Authentication string for the LRS (e.g., "Basic dXNlcm5hbWU6cGFzc3dvcmQ=")',
30
- )
31
- COLOR.command(
32
- null,
33
- '--xapi-actor',
34
- ' JSON string representing the xAPI actor (default: anonymous)',
35
- )
36
- COLOR.command(
37
- null,
38
- '--xapi-course-id',
39
- ' Custom identifier for the course (default: course URL)',
40
- )
41
- COLOR.command(
42
- null,
43
- '--xapi-course-title',
44
- ' Custom title for the course (default: from document)',
45
- )
46
- COLOR.command(
47
- null,
48
- '--xapi-mastery-threshold',
49
- ' Score threshold for mastery (default: 0.8)',
50
- )
51
- COLOR.command(
52
- null,
53
- '--xapi-progress-threshold',
54
- ' Score threshold for progress (default: 0.9)',
55
- )
56
- COLOR.command(
57
- null,
58
- '--xapi-debug',
59
- ' Enable debug logging for xAPI statements',
60
- )
61
- COLOR.command(
62
- null,
63
- '--xapi-zip',
64
- ' Package the output as a zip file',
65
- )
66
- }
67
-
68
- export const format = 'xapi'
69
-
70
- /**
71
- * Generate tincan.xml file for xAPI package
72
- * @param courseTitle The title of the course
73
- * @param courseDescription The description of the course
74
- * @param launchFile The HTML file to launch (usually index.html)
75
- * @param courseId The unique identifier for the course
76
- * @param resources Array of resource files to include in the package
77
- * @returns XML string for tincan.xml
78
- */
79
- function generateTincanXml(
80
- courseTitle: string,
81
- courseDescription: string,
82
- launchFile: string,
83
- courseId: string,
84
- resources: string[] = [],
85
- ) {
86
- // Create resource elements for all files
87
- const resourceElements = resources
88
- .map((resource) => {
89
- return ` <resource lang="en-us">${resource}</resource>`
90
- })
91
- .join('\n')
92
-
93
- return `<?xml version="1.0" encoding="utf-8" ?>
94
- <tincan xmlns="http://projecttincan.com/tincan.xsd">
95
- <activities>
96
- <activity id="${courseId}" type="course">
97
- <name>${courseTitle}</name>
98
- <description lang="en-US">${courseDescription}</description>
99
- <launch lang="en-us">${launchFile}</launch>
100
- ${resourceElements}
101
- </activity>
102
- </activities>
103
- </tincan>`
104
- }
105
-
106
- export interface XapiExportArguments {
107
- input: string
108
- readme: string
109
- output: string
110
- format: string
111
- path: string
112
- key?: string
113
- style?: string
114
- 'xapi-endpoint'?: string
115
- 'xapi-auth'?: string
116
- 'xapi-actor'?: string
117
- 'xapi-course-id'?: string
118
- 'xapi-course-title'?: string
119
- 'xapi-debug'?: boolean
120
- 'xapi-zip'?: boolean
121
- 'xapi-mastery-threshold'?: number
122
- 'xapi-progress-threshold'?: number
123
- }
124
-
125
- export async function exporter(argument: XapiExportArguments, json: any) {
126
- // make temp folder
127
- let tmp = await helper.tmpDir()
128
- const dirname = helper.dirname()
129
- let tmpPath = path.join(tmp, 'pro')
130
-
131
- // copy assets to temp
132
- await fs.copy(path.join(dirname, './assets/xapi'), tmpPath)
133
- await fs.copy(path.join(dirname, './assets/common'), tmpPath)
134
-
135
- // copy base path or readme-directory into temp
136
- await fs.copy(argument.path, tmpPath)
137
-
138
- // Read and modify index.html
139
- let index = fs.readFileSync(path.join(tmpPath, 'index.html'), 'utf8')
140
-
141
- // Change responsive key
142
- if (argument.key) {
143
- index = helper.injectResponsivevoice(argument.key, index)
144
- }
145
-
146
- console.log('Adding xAPI configuration ...', json.lia.sections.length)
147
-
148
- index = helper.inject('<script src="config.js"></script>', index)
149
- await helper.writeFile(
150
- path.join(tmpPath, 'config.js'),
151
- 'window.config_ = ' +
152
- JSON.stringify({
153
- task: json.task,
154
- quiz: json.quiz,
155
- survey: json.survey,
156
- masteryThreshold: argument['xapi-mastery-threshold'] || 0.8,
157
- progressThreshold: argument['xapi-progress-threshold'] || 0.9,
158
- totalSlides: json.lia.sections.length,
159
- }) +
160
- ';',
161
- )
162
-
163
- // Add default course
164
- index = helper.inject(
165
- `<script>
166
- if (!window.LIA) {
167
- window.LIA = {}
168
- }
169
- window.LIA.defaultCourseURL = "${path.basename(argument.readme)}"
170
- </script>`,
171
- index,
172
- )
173
-
174
- // Add xAPI configuration
175
- const xapiConfig = {
176
- endpoint: argument['xapi-endpoint'] || '',
177
- auth: argument['xapi-auth'] || '',
178
- actor: argument['xapi-actor']
179
- ? JSON.parse(argument['xapi-actor'])
180
- : {
181
- objectType: 'Agent',
182
- name: 'Anonymous',
183
- mbox: 'mailto:anonymous@example.com',
184
- },
185
- courseId: argument['xapi-course-id'] || '',
186
- courseTitle:
187
- argument['xapi-course-title'] || json.lia.str_title || 'LiaScript Course',
188
- debug: argument['xapi-debug'] || false,
189
- masteryThreshold: argument['xapi-mastery-threshold'] || 0.8,
190
- progressThreshold: argument['xapi-progress-threshold'] || 0.9,
191
- }
192
-
193
- // Add config UI if endpoint wasn't provided
194
- if (!argument['xapi-endpoint']) {
195
- index = helper.inject(
196
- `<script>
197
- // Store xAPI config in localStorage
198
- function saveXAPIConfig() {
199
- const endpoint = document.getElementById('xapi-endpoint').value;
200
- const auth = document.getElementById('xapi-auth').value;
201
- const actor = document.getElementById('xapi-actor').value;
202
- const masteryThreshold = parseFloat(document.getElementById('xapi-mastery-threshold').value) || 0.8;
203
- const progressThreshold = parseFloat(document.getElementById('xapi-progress-threshold').value) || 0.9;
204
-
205
- try {
206
- // Validate actor as JSON
207
- JSON.parse(actor);
208
-
209
- // Save to localStorage
210
- localStorage.setItem('xapi-config', JSON.stringify({
211
- endpoint,
212
- auth,
213
- actor: JSON.parse(actor),
214
- masteryThreshold,
215
- progressThreshold
216
- }));
217
-
218
- // Reload to apply settings
219
- window.location.reload();
220
- } catch (e) {
221
- alert('Invalid Actor JSON format. Please check your input.');
222
- }
223
- }
224
-
225
- // Load xAPI config from localStorage on page load
226
- document.addEventListener('DOMContentLoaded', function() {
227
- const storedConfig = localStorage.getItem('xapi-config');
228
- if (storedConfig) {
229
- const config = JSON.parse(storedConfig);
230
- window.xAPIConfig = config;
231
- }
232
-
233
- // Show/hide config panel
234
- const configPanel = document.getElementById('xapi-config-panel');
235
- if (configPanel) {
236
- document.getElementById('toggle-xapi-config').addEventListener('click', function() {
237
- configPanel.style.display = configPanel.style.display === 'none' ? 'block' : 'none';
238
- });
239
-
240
- // Populate fields if stored config exists
241
- if (storedConfig) {
242
- const config = JSON.parse(storedConfig);
243
- document.getElementById('xapi-endpoint').value = config.endpoint || '';
244
- document.getElementById('xapi-auth').value = config.auth || '';
245
- document.getElementById('xapi-actor').value = JSON.stringify(config.actor || {}, null, 2);
246
- document.getElementById('xapi-mastery-threshold').value = config.masteryThreshold || 0.8;
247
- document.getElementById('xapi-progress-threshold').value = config.progressThreshold || 0.9;
248
- }
249
- }
250
- });
251
- </script>
252
- <style>
253
- #xapi-config-panel {
254
- position: fixed;
255
- top: 0;
256
- right: 0;
257
- width: 400px;
258
- background: white;
259
- border: 1px solid #ccc;
260
- padding: 15px;
261
- box-shadow: 0 0 10px rgba(0,0,0,0.2);
262
- z-index: 9999;
263
- display: none;
264
- }
265
- #toggle-xapi-config {
266
- position: fixed;
267
- top: 10px;
268
- right: 10px;
269
- z-index: 9998;
270
- background: #f5f5f5;
271
- border: 1px solid #ccc;
272
- padding: 5px 10px;
273
- cursor: pointer;
274
- }
275
- </style>
276
- <div id="toggle-xapi-config">xAPI Settings</div>
277
- <div id="xapi-config-panel">
278
- <h3>xAPI LRS Configuration</h3>
279
- <div>
280
- <label for="xapi-endpoint">LRS Endpoint URL</label><br>
281
- <input type="text" id="xapi-endpoint" style="width: 100%" placeholder="https://your-lrs.com/data/xAPI/" value="">
282
- </div>
283
- <div style="margin-top: 10px">
284
- <label for="xapi-auth">Authentication (e.g., Basic dXNlcm5hbWU6cGFzc3dvcmQ=)</label><br>
285
- <input type="text" id="xapi-auth" style="width: 100%" placeholder="Basic dXNlcm5hbWU6cGFzc3dvcmQ=" value="">
286
- </div>
287
- <div style="margin-top: 10px">
288
- <label for="xapi-mastery-threshold">Mastery Threshold (0.0-1.0, default: 0.8)</label><br>
289
- <input type="number" id="xapi-mastery-threshold" style="width: 100%" placeholder="0.8" min="0" max="1" step="0.01" value="0.8">
290
- </div>
291
- <div style="margin-top: 10px">
292
- <label for="xapi-progress-threshold">Progress Threshold (0.0-1.0, default: 0.9)</label><br>
293
- <input type="number" id="xapi-progress-threshold" style="width: 100%" placeholder="0.9" min="0" max="1" step="0.01" value="0.9">
294
- </div>
295
- <div style="margin-top: 10px">
296
- <label for="xapi-actor">Actor (JSON format)</label><br>
297
- <textarea id="xapi-actor" style="width: 100%; height: 100px">{"objectType":"Agent","name":"Anonymous","mbox":"mailto:anonymous@example.com"}</textarea>
298
- </div>
299
- <div style="margin-top: 10px">
300
- <button onclick="saveXAPIConfig()">Save Configuration</button>
301
- </div>
302
- </div>`,
303
- index,
304
- )
305
- }
306
-
307
- // Set the window.xAPIConfig object with the base configuration
308
- index = helper.inject(
309
- `<script>
310
- window.xAPIConfig = ${JSON.stringify(xapiConfig, null, 2)};
311
- </script>`,
312
- index,
313
- )
314
-
315
- // Update title
316
- try {
317
- index = index.replace(
318
- '<title>Lia</title>',
319
- `<title>${json.lia.str_title}</title><meta property="og:title" content="${json.lia.str_title}"> <meta name="twitter:title" content="${json.lia.str_title}">`,
320
- )
321
- console.log('updating title ...')
322
- } catch (e) {
323
- console.warn('could not add title')
324
- }
325
-
326
- // Add description
327
- try {
328
- let description = json.lia.definition.macro.comment
329
- index = index.replace(
330
- '<meta name="description" content="LiaScript is a service for running free and interactive online courses, build with its own Markup-language. So check out the following course ;-)">',
331
- `<meta name="description" content="${description}"><meta property="og:description" content="${description}"><meta name="twitter:description" content="${description}">`,
332
- )
333
- console.log('updating description ...')
334
- } catch (e) {
335
- console.warn('could not add description')
336
- }
337
-
338
- // Add logo
339
- try {
340
- let logo = json.lia.definition.logo
341
- index = helper.inject(
342
- `<meta property="og:image" content="${logo}"><meta name="twitter:image" content="${logo}">`,
343
- index,
344
- )
345
- console.log('updating logo ...')
346
- } catch (e) {
347
- console.warn('could not add image')
348
- }
349
-
350
- // Add JSON-LD
351
- const jsonLD = await RDF.script(argument, json)
352
-
353
- try {
354
- index = helper.inject(jsonLD, index)
355
- index = helper.prettify(index)
356
- await helper.writeFile(path.join(tmpPath, 'index.html'), index)
357
- } catch (e) {
358
- console.warn(e)
359
- return
360
- }
361
-
362
- // Find all resources in the package
363
- const getAllFiles = function (dirPath: string, arrayOfFiles: string[] = []) {
364
- const files = fs.readdirSync(dirPath)
365
-
366
- files.forEach(function (file: string) {
367
- const filePath: string = path.join(dirPath, file)
368
- const stat = fs.statSync(filePath)
369
- if (stat.isDirectory()) {
370
- arrayOfFiles = getAllFiles(filePath, arrayOfFiles)
371
- } else {
372
- // Get path relative to tmpPath
373
- const relativePath: string = path.relative(tmpPath, filePath)
374
- // Only include files, not directories, and exclude tincan.xml itself
375
- if (relativePath && relativePath !== 'tincan.xml') {
376
- arrayOfFiles.push(relativePath)
377
- }
378
- }
379
- })
380
-
381
- return arrayOfFiles
382
- }
383
-
384
- const resources = getAllFiles(tmpPath)
385
-
386
- // Generate tincan.xml file
387
- const courseTitle = json.lia.str_title || 'LiaScript Course'
388
- const courseDescription =
389
- json.lia.definition?.macro?.comment || 'A LiaScript course'
390
- const courseId =
391
- argument['xapi-course-id'] ||
392
- `https://liascript.github.io/course/${helper.random(12)}`
393
- const tincanXml = generateTincanXml(
394
- courseTitle,
395
- courseDescription,
396
- 'index.html',
397
- courseId,
398
- resources,
399
- )
400
-
401
- // Write tincan.xml to the root of the package
402
- await helper.writeFile(path.join(tmpPath, 'tincan.xml'), tincanXml)
403
-
404
- // Create zip or move to output
405
- if (argument['xapi-zip']) {
406
- // Always create a zip for xAPI packages
407
- // Ensure output directory's parent exists
408
- const outputParent = path.dirname(argument.output)
409
- await fs.ensureDir(outputParent)
410
-
411
- // Create zip file
412
- helper.zip(tmpPath, argument.output)
413
- } else {
414
- // Ensure output directory's parent exists
415
- const outputParent = path.dirname(argument.output)
416
- await fs.ensureDir(outputParent)
417
-
418
- // Move files from temp to output
419
- await fs.move(tmpPath, argument.output, {
420
- filter: helper.filterHidden(argument.path),
421
- overwrite: true,
422
- })
423
- }
424
- }