@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.
- package/dist/assets/capacitor/{index.bfe7363b.js → index.a7f021f7.js} +1 -1
- package/dist/assets/capacitor/index.html +1 -1
- package/dist/assets/capacitor/{jszip.min.f6eda75b.js → jszip.min.43389eb1.js} +1 -1
- package/dist/assets/capacitor/{trystero-ipfs.min.b27a61d7.js → trystero-ipfs.min.f25fe3e7.js} +1 -1
- package/dist/assets/indexeddb/{index.599a57d6.js → index.4aceca2f.js} +1 -1
- package/dist/assets/indexeddb/index.html +1 -1
- package/dist/assets/indexeddb/{jszip.min.63142cc8.js → jszip.min.4fbcc13f.js} +1 -1
- package/dist/assets/scorm2004/{index.7a5820ab.js → index.33bec53a.js} +1 -1
- package/dist/assets/scorm2004/index.html +1 -1
- package/dist/assets/scorm2004/{jszip.min.63142cc8.js → jszip.min.4fbcc13f.js} +1 -1
- package/dist/assets/xapi/{index.018a032a.js → index.f2e89e49.js} +1 -1
- package/dist/assets/xapi/index.html +1 -1
- package/dist/assets/xapi/{jszip.min.eaecf580.js → jszip.min.19c66d77.js} +1 -1
- package/dist/index.js +47 -47
- package/dist/server/presets.json +94 -0
- package/dist/server/presets.yaml +120 -0
- package/dist/server/public/app.js +1 -0
- package/dist/server/public/assets/android.svg +38 -0
- package/dist/server/public/assets/cmi.svg +154 -0
- package/dist/server/public/assets/docx.svg +20 -0
- package/dist/server/public/assets/edX.svg +75 -0
- package/dist/server/public/assets/edx.svg +75 -0
- package/dist/server/public/assets/epub.svg +18 -0
- package/dist/server/public/assets/icon.svg +82 -0
- package/dist/server/public/assets/ilias.png +0 -0
- package/dist/server/public/assets/json.svg +4 -0
- package/dist/server/public/assets/learnworlds.png +0 -0
- package/dist/server/public/assets/moodle.svg +190 -0
- package/dist/server/public/assets/opal.png +0 -0
- package/dist/server/public/assets/openolat.png +0 -0
- package/dist/server/public/assets/pdf.svg +4 -0
- package/dist/server/public/assets/rdf.svg +4 -0
- package/dist/server/public/assets/scorm.png +0 -0
- package/dist/server/public/assets/web.png +0 -0
- package/dist/server/public/assets/xapi.png +0 -0
- package/dist/server/public/i18n.js +1 -0
- package/dist/server/public/index.html +1587 -0
- package/dist/server/public/locales/de.json +247 -0
- package/dist/server/public/locales/en.json +247 -0
- package/dist/server/public/status.html +251 -0
- package/dist/server/public/styles.css +712 -0
- package/package.json +5 -1
- package/.parcelrc +0 -3
- package/DESKTOP_APP_README.md +0 -58
- package/DOCKERHUB_DESCRIPTION.md +0 -52
- package/Dockerfile +0 -129
- package/PLAYSTORE_GUIDE.md +0 -172
- package/action.yml +0 -157
- package/custom.css +0 -10
- package/electron-builder.json +0 -149
- package/src/cli.ts +0 -69
- package/src/colorize.ts +0 -115
- package/src/export/android.ts +0 -419
- package/src/export/docx.ts +0 -1025
- package/src/export/epub.ts +0 -1306
- package/src/export/h5p.ts +0 -390
- package/src/export/helper.ts +0 -360
- package/src/export/ims.ts +0 -191
- package/src/export/pdf.ts +0 -406
- package/src/export/presets.ts +0 -220
- package/src/export/project.ts +0 -829
- package/src/export/rdf.ts +0 -551
- package/src/export/scorm12.ts +0 -167
- package/src/export/scorm2004.ts +0 -140
- package/src/export/web.ts +0 -306
- package/src/export/xapi.ts +0 -424
- package/src/exporter.ts +0 -296
- package/src/index.ts +0 -96
- package/src/parser.ts +0 -373
- package/src/presets.yaml +0 -219
- package/src/types.ts +0 -82
- package/tsconfig.json +0 -24
package/src/export/project.ts
DELETED
|
@@ -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
|
-
}
|