@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,829 +0,0 @@
1
- import * as helper from './helper'
2
- import * as PDF from './pdf'
3
- import * as IMS from './ims'
4
- import * as SCORM12 from './scorm12'
5
- import * as SCORM2004 from './scorm2004'
6
- import * as ANDROID from './android'
7
- import * as RDF from './rdf'
8
- import * as COLOR from '../colorize'
9
-
10
- const fs = require('fs-extra')
11
- const path = require('path')
12
- const { execSync } = require('child_process')
13
-
14
- var Categories: Set<string> = new Set([])
15
-
16
- export function getNext(collection: any): string | null {
17
- if (collection['collection']) {
18
- collection = collection['collection']
19
- }
20
-
21
- if (collection['url'] && collection['data'] === undefined) {
22
- return collection['url']
23
- } else {
24
- for (let i = 0; i < collection.length; i++) {
25
- let course = collection[i]
26
-
27
- if (course.collection) {
28
- let url = getNext(course)
29
-
30
- if (url) {
31
- return url
32
- }
33
- } else if (course.url && course.data === undefined) {
34
- return course.url
35
- }
36
- }
37
- }
38
- return null
39
- }
40
-
41
- export function storeNext(collection: any, data: any) {
42
- if (collection['collection']) {
43
- collection = collection['collection']
44
- }
45
-
46
- for (let i = 0; i < collection.length; i++) {
47
- if (collection[i].collection) {
48
- for (let j = 0; j < collection[i].collection.length; j++) {
49
- if (
50
- collection[i].collection[j].url &&
51
- collection[i].collection[j].data === undefined
52
- ) {
53
- collection[i].collection[j].data = data
54
- return
55
- }
56
- }
57
- } else if (collection[i].url && collection[i].data === undefined) {
58
- collection[i].data = data
59
- return
60
- }
61
- }
62
-
63
- return
64
- }
65
-
66
- export function help() {
67
- console.log('')
68
- console.log(COLOR.heading('Project settings:'), '\n')
69
-
70
- COLOR.info(
71
- 'A project is a bundle for multiple LiaScript resource into a single project overview page, based on a provided yaml description.'
72
- )
73
-
74
- console.log(
75
- '\nLearn more: https://www.npmjs.com/package/@liascript/exporter#project \n'
76
- )
77
- console.log('Example:')
78
- console.log(
79
- '- Input: https://github.com/LiaBooks/liabooks.github.com/blob/main/project.yaml'
80
- )
81
- console.log('- Output: https://liabooks.github.io')
82
- console.log('')
83
-
84
- COLOR.command(
85
- null,
86
- '--project-no-meta',
87
- ' Disable the generation of meta information for OpenGraph and Twitter-cards.'
88
- )
89
- COLOR.command(
90
- null,
91
- '--project-no-rdf',
92
- ' Disable the generation of json-ld.'
93
- )
94
- COLOR.command(
95
- null,
96
- '--project-no-categories',
97
- ' Disable the filter for categories/tags.'
98
- )
99
- COLOR.command(
100
- null,
101
- '--project-category-blur',
102
- ' Enable this and the categories will be blurred instead of deleted.'
103
- )
104
- COLOR.command(
105
- null,
106
- '--project-generate-scrom12',
107
- 'SCORM12 and pass additional scrom settings.'
108
- )
109
- COLOR.command(
110
- null,
111
- '--project-generate-scrom2004',
112
- 'SCORM2004 and pass additional scrom settings.'
113
- )
114
- COLOR.command(
115
- null,
116
- '--project-generate-ims',
117
- ' IMS resources with additional config settings.'
118
- )
119
- COLOR.command(
120
- null,
121
- '--project-generate-pdf',
122
- ' PDFs are automatically generated and added to every card.'
123
- )
124
- COLOR.command(
125
- null,
126
- '--project-generate-cache',
127
- ' Only generate new files, if they do not exist.'
128
- )
129
- }
130
-
131
- export interface ProjectExportArguments {
132
- input: string
133
- readme: string
134
- output: string
135
- format: string
136
- path: string
137
- key?: string
138
- style?: string
139
- 'project-no-meta'?: boolean
140
- 'project-no-rdf'?: boolean
141
- 'project-no-categories'?: boolean
142
- 'project-category-blur'?: number
143
- 'project-generate-pdf'?: boolean
144
- 'project-generate-ims'?: boolean
145
- 'project-generate-scorm12'?: boolean
146
- 'project-generate-scorm2004'?: boolean
147
- 'project-generate-android'?: boolean
148
- 'project-generate-cache'?: boolean
149
- }
150
-
151
- export const format = 'project'
152
-
153
- export async function exporter(argument: ProjectExportArguments, json: any) {
154
- // make temp folder
155
-
156
- let cards = ''
157
- const output = argument.output
158
- const itemList: any[] = []
159
-
160
- for (let i = 0; i < json.collection.length; i++) {
161
- let course = json.collection[i]
162
-
163
- if (course.collection) {
164
- let subCards = ''
165
- let subItemList: any[] = []
166
-
167
- for (let j = 0; j < course.collection.length; j++) {
168
- if (course.collection[j].link) {
169
- subCards += `<div class='col-sm-6 col-md-4 col-lg-3 ${
170
- course.grid ? 'mb-3' : ''
171
- }'>
172
- ${toLinkCard(argument, course.collection[j], true)}
173
- </div>`
174
- } else {
175
- let { html, json } = await toCard(
176
- argument,
177
- course.collection[j],
178
- true
179
- )
180
-
181
- subCards += `<div class='col-sm-6 col-md-4 col-lg-3 ${
182
- course.grid ? 'mb-3' : ''
183
- }'>
184
- ${html}
185
- </div>`
186
-
187
- subItemList.push(json)
188
- }
189
- }
190
-
191
- const itemListElement = {
192
- '@type': 'ItemList',
193
- itemListElement: subItemList,
194
- }
195
-
196
- if (course.title) {
197
- itemListElement['name'] = course.title
198
- }
199
- if (course.comment) {
200
- itemListElement['description'] = course.comment
201
- }
202
-
203
- itemList.push(itemListElement)
204
-
205
- cards += `
206
- <div class="col-12">
207
- <div class="card">
208
- <div class="card-header">
209
- ${course.title}
210
- </div>
211
- <div class="card-body">
212
- <p class="card-text">${course.comment}</p>
213
- <div ${
214
- course.grid
215
- ? 'class="row"'
216
- : 'style="display: flex; scroll-snap-type: x mandatory; overflow-x: auto; overflow-y: hidden; padding-bottom: 10px"'
217
- }>
218
- ${subCards}
219
- </div>
220
- </div>
221
- </div>
222
- </div>`
223
- } else if (course.html) {
224
- cards += "<div class='col-12'>" + course.html + '</div>'
225
- } else if (course.link) {
226
- cards += "<div class='col'>" + toLinkCard(argument, course) + '</div>'
227
- } else {
228
- let { html, json } = await toCard(argument, course)
229
-
230
- cards += "<div class='col'>" + html + '</div>'
231
-
232
- itemList.push(json)
233
- }
234
- }
235
-
236
- const background = json.logo
237
- ? `style="background-size: cover; background-image: url('${json.logo}'); background-position: center center; background-repeat: no-repeat;"`
238
- : ''
239
-
240
- let options = ''
241
-
242
- if (Categories.size > 0 && !argument['project-no-categories']) {
243
- const opt = [...Categories].sort()
244
-
245
- for (let i = 0; i < opt.length; i++) {
246
- options += `<option value="${opt[i]}">${opt[i]}</option>`
247
- }
248
-
249
- options =
250
- `<select id="categorySelect"
251
- class="form-select"
252
- aria-label="Default select example"
253
- onchange="addCategoryChip(this.value)">
254
- <option value="" selected>All categories</option>` +
255
- options +
256
- '</select>'
257
- }
258
-
259
- const jsonLD = {
260
- '@context': 'http://schema.org/',
261
- '@type': 'ItemList',
262
- itemListElement: removeContext(itemList),
263
- }
264
-
265
- let title = json.title || 'LiaScript Course Index'
266
-
267
- if (json.title) {
268
- title = cleanHTML(title).replace(/\s+/g, ' ').trim()
269
- jsonLD['name'] = title
270
- }
271
-
272
- if (json.comment) {
273
- jsonLD['description'] = cleanHTML(json.comment).replace(/\s+/g, ' ').trim()
274
- }
275
-
276
- const html = `<!DOCTYPE html>
277
- <html>
278
- <head>
279
- <title>${title}</title>
280
-
281
- <script type="application/ld+json">
282
- ${JSON.stringify(jsonLD, null, 2)}
283
- </script>
284
-
285
- ${
286
- json.icon
287
- ? '<link rel="icon" type="image/x-icon" href="' + json.icon + '">'
288
- : ''
289
- }
290
-
291
- <meta name="viewport" content="width=device-width, initial-scale=1">
292
- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
293
-
294
- <script>
295
- // Globale Variable zum Speichern der ausgewählten Kategorien
296
- window.selectedCategories = []
297
-
298
- // Fügt einen Chip hinzu, wenn eine Kategorie gewählt wurde
299
- function addCategoryChip(category) {
300
- if (!category) return // falls "All categories" gewählt wurde, nichts tun
301
- if (window.selectedCategories.indexOf(category) === -1) {
302
- window.selectedCategories.push(category)
303
- // Option im Select-Menü deaktivieren
304
- document.querySelector('#categorySelect option[value="' + category + '"]').disabled = true
305
- updateChipsDisplay()
306
- filterCards()
307
- }
308
- // Setze das Select-Element zurück
309
- document.getElementById('categorySelect').value = ''
310
- }
311
-
312
- // Entfernt einen Chip
313
- function removeCategoryChip(category) {
314
- const index = window.selectedCategories.indexOf(category)
315
- if (index > -1) {
316
- window.selectedCategories.splice(index, 1)
317
- // Option im Select-Menü wieder aktivieren
318
- document.querySelector('#categorySelect option[value="' + category + '"]').disabled = false
319
- updateChipsDisplay()
320
- filterCards()
321
- }
322
- }
323
-
324
- // Aktualisiert die Anzeige der Chips
325
- function updateChipsDisplay() {
326
- const chipsContainer = document.getElementById('chipsContainer')
327
- chipsContainer.innerHTML = ''
328
- window.selectedCategories.forEach(function (cat) {
329
- const chip = document.createElement('span')
330
- chip.className = 'badge rounded-pill bg-primary me-2'
331
- chip.style.cursor = 'pointer'
332
- chip.style.fontSize = '1rem'
333
- chip.textContent = cat + ' ×'
334
- chip.onclick = function () {
335
- removeCategoryChip(cat)
336
- }
337
- chipsContainer.appendChild(chip)
338
- })
339
- }
340
-
341
- function filterCards() {
342
- const cards = document.querySelectorAll('div[data-category]')
343
- cards.forEach(function (card) {
344
- // Falls keine Filterkategorien ausgewählt wurden, zeige alle Karten
345
- if (window.selectedCategories.length === 0) {
346
- ${
347
- argument['project-category-blur']
348
- ? 'card.style.filter = "";'
349
- : 'card.parentNode.style.display = "block";'
350
- }
351
- return
352
- }
353
- // Zerlege die im data-Attribut hinterlegten Kategorien
354
- const cardCategories = card.dataset.category.split('|')
355
- // Prüfe, ob alle ausgewählten Kategorien in der Karte vorhanden sind
356
- const show = window.selectedCategories.every(function (cat) {
357
- return cardCategories.indexOf(cat) !== -1
358
- })
359
- if (show) {
360
- ${
361
- argument['project-category-blur']
362
- ? 'card.style.filter = "";'
363
- : 'card.parentNode.style.display = "block";'
364
- }
365
- } else {
366
- ${
367
- argument['project-category-blur']
368
- ? 'card.style.filter = "blur(1px) opacity(35%)";'
369
- : 'card.parentNode.style.display = "none";'
370
- }
371
- }
372
- })
373
- }
374
- </script>
375
- </head>
376
- <body>
377
-
378
- <main>
379
- <div class="container-fluid" ${background} >
380
- <section class="py-5 text-center container">
381
- <div class="row py-lg-5">
382
- <div class="col-lg-6 col-md-8 mx-auto">
383
- <h1 class="fw-light">${
384
- json.title || 'LiaScript Course Index'
385
- }</h1>
386
- <p class="lead text-muted">${json.comment || ''}</p>
387
-
388
- ${options}
389
- <div id="chipsContainer" class="mt-3"></div>
390
- </div>
391
- </div>
392
- </section>
393
- </div>
394
-
395
- <div class="album py-5 bg-light">
396
- <div class="container">
397
- <div class="row row-cols-1 row-cols-sm-1 row-cols-md-2 row-cols-xl-3 g-3">
398
- ${cards}
399
- </div>
400
- </div>
401
- </div>
402
-
403
- </main>
404
-
405
-
406
- <footer class="text-muted py-3">
407
- <div class="container">
408
- <p class="float-end">
409
- <a href="#">Back to top</a>
410
- </p>
411
- <p>${
412
- json.footer ||
413
- '<a href="https://liascript.github.io" target="_blank">LiaScript</a> is a Markdown dialect made for education. For more information checkout out <a href="https://www.youtube.com/channel/UCyiTe2GkW_u05HSdvUblGYg" target="_blank">YouTube-Channel</a> or follow us on <a href="https://twitter.com/LiaScript" target="_blank">Twitter</a>.'
414
- }</p>
415
- </div>
416
- </footer>
417
-
418
- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
419
- </body>
420
- </html>
421
- `
422
-
423
- helper.writeFile(output + '.html', helper.prettify(helper.prettify(html)))
424
- }
425
-
426
- function removeContext(obj) {
427
- for (let key in obj) {
428
- if (obj.hasOwnProperty(key)) {
429
- if (key === '@context') {
430
- delete obj[key]
431
- } else if (typeof obj[key] === 'object') {
432
- removeContext(obj[key])
433
- }
434
- }
435
- }
436
- return obj
437
- }
438
- async function moveFile(oldPath, newPath) {
439
- // 1. Create the destination directory if it does not exist
440
- // Set the `recursive` option to `true` to create all the subdirectories
441
-
442
- await fs.mkdir(path.dirname(newPath), { recursive: true })
443
- // 2. Rename the file (move it to the new directory)
444
- // Return the promise
445
- return fs.rename(oldPath, newPath)
446
- }
447
-
448
- function cleanHTML(html: string) {
449
- return html.replace(/<[^>]+>/g, '')
450
- }
451
-
452
- function meta(json: any) {
453
- const title =
454
- json.meta?.title || cleanHTML(json.title) || 'LiaScript Course Index'
455
-
456
- const description = json.meta?.description || cleanHTML(json.comment)
457
-
458
- const image = json.meta?.image || json.logo
459
-
460
- return `<meta property="og:type" content="website">
461
- <meta property="og:title" content="${title}">
462
- <meta property="og:description" content="${description}">
463
- <meta property="og:image" content="${image}">
464
-
465
- <meta name="twitter:title" content="${title}">
466
- <meta name="twitter:description" content="${description}">
467
- <meta name="twitter:image" content="${image}">
468
- `
469
- }
470
-
471
- function overwrite(check, defaultsTo) {
472
- return check === null ? null : check || defaultsTo
473
- }
474
-
475
- function hash(url: string) {
476
- const value = url
477
- .split('')
478
- .map((v) => v.charCodeAt(0))
479
- .reduce((a, v) => (a + ((a << 7) + (a << 3))) ^ v)
480
- .toString(16)
481
-
482
- return value.startsWith('-') ? '0' + value.slice(1) : value
483
- }
484
-
485
- function toLinkCard(
486
- argument: any,
487
- course: any,
488
- small: boolean = false
489
- ): string {
490
- if (course.arguments) {
491
- argument = course.arguments.reduce((a, b) => {
492
- return { ...a, ...b }
493
- }, argument)
494
- }
495
-
496
- let tags = []
497
-
498
- const tagList = course.tags || tags
499
- for (let i = 0; i < tagList.length; i++) {
500
- Categories.add(tagList[i].toLowerCase())
501
- }
502
-
503
- let comment = course.title ? course.comment : course.comment || course.link
504
-
505
- return card(
506
- small,
507
- '',
508
- course.title || '',
509
- comment || '',
510
- tagList,
511
- {},
512
- course.logo,
513
- course.link
514
- )
515
- }
516
-
517
- async function toCard(
518
- argument: any,
519
- course: any,
520
- small: boolean = false
521
- ): Promise<{ html: string; json: any }> {
522
- // if other parameters are defined for a specific course
523
- // then they are treated
524
-
525
- if (course.arguments) {
526
- argument = course.arguments.reduce((a, b) => {
527
- return { ...a, ...b }
528
- }, argument)
529
- }
530
-
531
- let tags
532
- try {
533
- tags = course.data.lia.definition.macro.tags
534
- .split(',')
535
- .map((e: string) => e.trim())
536
- } catch (e) {
537
- tags = []
538
- }
539
-
540
- const backupOutput = hash(course.data.lia.readme)
541
-
542
- const tagList = course.tags || tags
543
- for (let i = 0; i < tagList.length; i++) {
544
- Categories.add(tagList[i].toLowerCase())
545
- }
546
-
547
- let downloads = {}
548
-
549
- if (argument['project-generate-pdf'])
550
- downloads['pdf'] = 'assets/pdf/' + backupOutput + '.pdf'
551
- if (argument['project-generate-ims'])
552
- downloads['ims'] = 'assets/ims/' + backupOutput + '.zip'
553
- if (argument['project-generate-scorm12'])
554
- downloads['scorm12'] = 'assets/scorm12/' + backupOutput + '.zip'
555
- if (argument['project-generate-scorm2004'])
556
- downloads['scorm2004'] = 'assets/scorm2004/' + backupOutput + '.zip'
557
-
558
- if (argument['project-generate-pdf']) {
559
- argument.input = course.data.lia.readme
560
- argument.output = backupOutput
561
-
562
- const file = argument.output + '.pdf'
563
-
564
- if (
565
- argument['project-generate-cache'] &&
566
- fs.existsSync(path.join(process.cwd(), 'assets/pdf/' + file))
567
- ) {
568
- console.log('using cached file of ', argument.input, ' -> ', file)
569
- } else {
570
- console.log('generate pdf of', argument.input, ' -> ', file)
571
-
572
- await PDF.exporter(argument, {})
573
-
574
- if (fs.existsSync(file)) {
575
- await moveFile(file, 'assets/pdf/' + file)
576
- }
577
- }
578
- }
579
-
580
- let repo
581
- if (
582
- argument['project-generate-ims'] ||
583
- argument['project-generate-scorm12'] ||
584
- argument['project-generate-scorm2004'] ||
585
- argument['project-generate-android']
586
- ) {
587
- repo = helper.getRepository(course.url)
588
-
589
- if (repo) {
590
- execSync(repo.cmd)
591
- argument.input = path.join('tmp', repo.path)
592
- argument.path = 'tmp'
593
- argument.readme = path.join('./', repo.path)
594
-
595
- argument.output = backupOutput
596
-
597
- execSync('rm -rf tmp/.git')
598
- execSync('rm -rf tmp/.github')
599
- execSync('rm -rf tmp/.gitignore')
600
- }
601
- }
602
-
603
- // IMS
604
- if (repo && argument['project-generate-ims']) {
605
- argument.output = 'assets/ims/' + backupOutput
606
- const file = argument.output + '.zip'
607
-
608
- try {
609
- execSync('mkdir assets/ims')
610
- } catch (e) {}
611
-
612
- if (
613
- argument['project-generate-cache'] &&
614
- fs.existsSync(path.join(process.cwd(), file))
615
- ) {
616
- console.log('using cached file of ', argument.input, ' -> ', file)
617
- } else {
618
- await IMS.exporter(argument, course.data)
619
- }
620
- }
621
-
622
- // SCORM12
623
- if (repo && argument['project-generate-scorm12']) {
624
- argument.output = 'assets/scrom12/' + backupOutput
625
- const asset = argument.output + '.zip'
626
-
627
- if (
628
- argument['project-generate-cache'] &&
629
- fs.existsSync(path.join(process.cwd(), asset))
630
- ) {
631
- console.log('using cached file of ', argument.input, ' -> ', asset)
632
- } else {
633
- await SCORM12.exporter(argument, course.data)
634
- }
635
- }
636
-
637
- // SCORM2004
638
- if (repo && argument['project-generate-scorm2004']) {
639
- argument.output = 'assets/scorm2004/' + backupOutput
640
-
641
- const asset = argument.output + '.zip'
642
-
643
- if (
644
- argument['project-generate-cache'] &&
645
- fs.existsSync(path.join(process.cwd(), asset))
646
- ) {
647
- console.log('using cached file of ', argument.input, ' -> ', asset)
648
- } else {
649
- await SCORM2004.exporter(argument, course.data)
650
- }
651
- }
652
-
653
- // Android
654
- if (repo && argument['project-generate-android']) {
655
- argument.output = backupOutput
656
- const file = argument.output + '.apk'
657
-
658
- const asset = 'assets/android/' + file
659
-
660
- if (
661
- argument['project-generate-cache'] &&
662
- fs.existsSync(path.join(process.cwd(), asset))
663
- ) {
664
- downloads['apk'] = asset
665
- } else {
666
- await ANDROID.exporter(argument, course.data)
667
-
668
- if (fs.existsSync(file)) {
669
- await moveFile(file, asset)
670
- downloads['apk'] = asset
671
- }
672
- }
673
- }
674
-
675
- // clean up
676
- if (repo) {
677
- execSync('rm -rf tmp')
678
- }
679
-
680
- argument['rdf-url'] = course.data.lia.readme
681
-
682
- const rslt = {
683
- html: card(
684
- small,
685
- course.data.lia.readme,
686
- overwrite(course.title, course.data.lia.str_title),
687
- overwrite(course.comment, course.data.lia.comment),
688
- tagList,
689
- downloads,
690
- overwrite(course.logo, course.data.lia.definition.logo)
691
- ),
692
- json: await RDF.parse(argument, course.data),
693
- }
694
-
695
- return rslt
696
- }
697
-
698
- function card(
699
- small: boolean,
700
- url: string,
701
- title: string,
702
- comment: string,
703
- tags: string[],
704
- download: {
705
- pdf?: string
706
- scorm12?: string
707
- scorm2004?: string
708
- ims?: string
709
- apk?: string
710
- },
711
- img_url?: string,
712
- link?: string
713
- ): string {
714
- let image = ''
715
- if (img_url) {
716
- if (!(img_url.startsWith('http:') || img_url.startsWith('https:'))) {
717
- const fullImageUrl = new URL(img_url, url)
718
-
719
- img_url = fullImageUrl.toString()
720
- }
721
-
722
- image =
723
- //`<img src="${img_url}" class="card-img-top" alt="">`
724
- `<div class="card-img-top" style="background-size: cover; height: 175px; background-image: url('${img_url}'); background-position: center center; background-repeat: no-repeat;"></div>`
725
- }
726
- /*
727
- else {
728
- image = `<svg class="bd-placeholder-img card-img-top" width="100%" height="175" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Placeholder: Thumbnail" preserveAspectRatio="xMidYMid slice" focusable="false"><title>Placeholder</title><rect width="100%" height="100%" fill="${stringToColor(
729
- title
730
- )}"></rect></svg>`
731
- }
732
- */
733
-
734
- let tag_list = ''
735
-
736
- if (tags.length > 0) {
737
- for (let i = 0; i < tags.length; i++) {
738
- tag_list += `<span style="display: inline; white-space: break-spaces;" class="badge rounded-pill bg-light text-dark">${tags[i]}</span>`
739
- }
740
-
741
- tag_list = `<p>${tag_list}</p>`
742
- }
743
-
744
- if (small && comment) {
745
- comment = '<small>' + comment + '</small>'
746
- }
747
-
748
- let footer = ''
749
-
750
- if (Object.keys(download).length > 0) {
751
- footer = `<div class="card-footer">
752
- <div class="dropdown">
753
- <a class="btn btn-secondary btn-sm dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-bs-toggle="dropdown" aria-expanded="false">
754
- Download as ...
755
- </a>
756
-
757
- <ul class="dropdown-menu" aria-labelledby="dropdownMenuLink" style="">
758
- ${
759
- download.pdf
760
- ? '<li><a class="dropdown-item btn-sm" target="_blank" href="' +
761
- download.pdf +
762
- '">PDF</a></li>'
763
- : ''
764
- }
765
- ${
766
- download.scorm12
767
- ? '<li><a class="dropdown-item btn-sm" href="' +
768
- download.scorm12 +
769
- '">SCORM 1.2</a></li>'
770
- : ''
771
- }
772
- ${
773
- download.scorm2004
774
- ? '<li><a class="dropdown-item btn-sm" href="' +
775
- download.scorm2004 +
776
- '">SCORM 2004</a></li>'
777
- : ''
778
- }
779
- ${
780
- download.ims
781
- ? '<li><a class="dropdown-item btn-sm" href="' +
782
- download.ims +
783
- '">IMS Content Packaging</a></li>'
784
- : ''
785
- }
786
- ${
787
- download.apk
788
- ? '<li><a class="dropdown-item btn-sm" href="' +
789
- download.apk +
790
- '">Android APK</a></li>'
791
- : ''
792
- }
793
- </ul>
794
- </div>
795
- </div>
796
- `
797
- }
798
-
799
- return `<div class="card shadow-sm m-1" style="height: 100%" data-category="${tags
800
- .map((e) => e.toLowerCase())
801
- .join('|')}">
802
- ${image}
803
- <div class="card-body" style="transform: rotate(0);">
804
- <a href="${link ? '' : 'https://liascript.github.io/course/?'}${
805
- link || url
806
- }" target="${
807
- link && !link.startsWith('http') ? '_self' : '_blank'
808
- }" class="link-dark stretched-link">
809
- <h${small ? 6 : 5} class="card-title">${title}</h${small ? 6 : 5}>
810
- </a>
811
- <p class="card-text">${comment}</p>
812
- ${tag_list}
813
- </div>
814
- ${footer}
815
- </div>`
816
- }
817
-
818
- function stringToColor(str: string) {
819
- var hash = 0
820
- for (var i = 0; i < str.length; i++) {
821
- hash = str.charCodeAt(i) + ((hash << 5) - hash)
822
- }
823
- var color = '#'
824
- for (var i = 0; i < 3; i++) {
825
- var value = (hash >> (i * 8)) & 0xff
826
- color += ('00' + value.toString(16)).substr(-2)
827
- }
828
- return color
829
- }