@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/h5p.ts
DELETED
|
@@ -1,390 +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
|
-
const archiver = require('archiver')
|
|
8
|
-
|
|
9
|
-
export function help() {
|
|
10
|
-
console.log('')
|
|
11
|
-
console.log(COLOR.heading('H5P settings:'), '\n')
|
|
12
|
-
|
|
13
|
-
COLOR.info(
|
|
14
|
-
'H5P is a free and open-source content collaboration framework based on JavaScript that makes it easy to create, share and reuse interactive HTML5 content.'
|
|
15
|
-
)
|
|
16
|
-
console.log('\nLearn more: https://h5p.org/\n')
|
|
17
|
-
|
|
18
|
-
COLOR.command(
|
|
19
|
-
null,
|
|
20
|
-
'--h5p-embed',
|
|
21
|
-
' embed the Markdown into the JS code'
|
|
22
|
-
)
|
|
23
|
-
COLOR.command(
|
|
24
|
-
null,
|
|
25
|
-
'--h5p-iframe',
|
|
26
|
-
' use an iframe for content display'
|
|
27
|
-
)
|
|
28
|
-
COLOR.command(
|
|
29
|
-
null,
|
|
30
|
-
'--h5p-zip',
|
|
31
|
-
' package the output as a .h5p file'
|
|
32
|
-
)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export const format = 'h5p'
|
|
36
|
-
|
|
37
|
-
export async function exporter(
|
|
38
|
-
argument: {
|
|
39
|
-
input: string
|
|
40
|
-
readme: string
|
|
41
|
-
output: string
|
|
42
|
-
format: string
|
|
43
|
-
path: string
|
|
44
|
-
key?: string
|
|
45
|
-
style?: string
|
|
46
|
-
|
|
47
|
-
// special cases for H5P
|
|
48
|
-
'h5p-embed'?: string
|
|
49
|
-
'h5p-iframe'?: boolean
|
|
50
|
-
'h5p-zip'?: boolean
|
|
51
|
-
},
|
|
52
|
-
json: any
|
|
53
|
-
) {
|
|
54
|
-
// make temp folder
|
|
55
|
-
let tmp = await helper.tmpDir()
|
|
56
|
-
const dirname = helper.dirname()
|
|
57
|
-
|
|
58
|
-
// Create a standard H5P package structure - this MUST be at the root level, not in subdirectories
|
|
59
|
-
let h5pRoot = path.join(tmp, 'h5p_package')
|
|
60
|
-
await fs.ensureDir(h5pRoot)
|
|
61
|
-
|
|
62
|
-
// Extract the markdown content
|
|
63
|
-
const markdownContent =
|
|
64
|
-
argument['h5p-embed'] ||
|
|
65
|
-
(fs.existsSync(path.join(argument.path, argument.readme))
|
|
66
|
-
? fs.readFileSync(path.join(argument.path, argument.readme), 'utf8')
|
|
67
|
-
: '# LiaScript Content\n\nThis content was exported from LiaScript.')
|
|
68
|
-
|
|
69
|
-
// Save the markdown content directly to the root with .md extension (allowed in whitelist)
|
|
70
|
-
await helper.writeFile(
|
|
71
|
-
path.join(h5pRoot, 'liascript_content.md'),
|
|
72
|
-
markdownContent
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
// Create h5p.json metadata file (required for all H5P packages)
|
|
76
|
-
await helper.writeFile(
|
|
77
|
-
path.join(h5pRoot, 'h5p.json'),
|
|
78
|
-
JSON.stringify(
|
|
79
|
-
{
|
|
80
|
-
title: json.lia.str_title || 'LiaScript Course',
|
|
81
|
-
language: json.lia.definition.language || 'en',
|
|
82
|
-
mainLibrary: 'H5P.Text',
|
|
83
|
-
embedTypes: ['iframe'],
|
|
84
|
-
preloadedDependencies: [
|
|
85
|
-
{
|
|
86
|
-
machineName: 'H5P.Text',
|
|
87
|
-
majorVersion: 1,
|
|
88
|
-
minorVersion: 1,
|
|
89
|
-
},
|
|
90
|
-
],
|
|
91
|
-
author: json.lia.definition.author || '',
|
|
92
|
-
license: 'CC BY-SA',
|
|
93
|
-
licenseVersion: '4.0',
|
|
94
|
-
description: json.lia.comment || '',
|
|
95
|
-
contentType: 'Interactive Course',
|
|
96
|
-
},
|
|
97
|
-
null,
|
|
98
|
-
2
|
|
99
|
-
)
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
// First, copy the LiaScript assets to the temp directory
|
|
103
|
-
let liaAssetPath = path.join(tmp, 'lia_assets')
|
|
104
|
-
await fs.copy(path.join(dirname, './assets/h5p'), liaAssetPath)
|
|
105
|
-
// await fs.copy(path.join(dirname, './assets/common'), liaAssetPath)
|
|
106
|
-
|
|
107
|
-
// Generate the self-contained HTML
|
|
108
|
-
const indexPath = path.join(liaAssetPath, 'index.html')
|
|
109
|
-
const selfContainedHtml = await createSelfContainedHtml(
|
|
110
|
-
indexPath,
|
|
111
|
-
liaAssetPath,
|
|
112
|
-
markdownContent // Pass the markdown content as a parameter
|
|
113
|
-
)
|
|
114
|
-
|
|
115
|
-
// Create content.json with the self-contained HTML
|
|
116
|
-
const contentJson = {
|
|
117
|
-
text: selfContainedHtml,
|
|
118
|
-
metadata: {
|
|
119
|
-
contentType: 'Text',
|
|
120
|
-
license: 'U',
|
|
121
|
-
title: json.lia.str_title || 'LiaScript Course',
|
|
122
|
-
authors: [
|
|
123
|
-
{
|
|
124
|
-
name: json.lia.definition.author || 'LiaScript Author',
|
|
125
|
-
role: 'Author',
|
|
126
|
-
},
|
|
127
|
-
],
|
|
128
|
-
},
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Save content.json directly to the root
|
|
132
|
-
await helper.writeFile(
|
|
133
|
-
path.join(h5pRoot, 'content.json'),
|
|
134
|
-
JSON.stringify(contentJson, null, 2)
|
|
135
|
-
)
|
|
136
|
-
|
|
137
|
-
// Now copy the H5P assets AFTER creating the basic structure
|
|
138
|
-
try {
|
|
139
|
-
// Copy the content files from the H5P templates - these should be pre-structured correctly
|
|
140
|
-
await fs.copy(path.join(dirname, './assets/h5p'), h5pRoot, {
|
|
141
|
-
overwrite: false, // Don't overwrite existing files (like content.json)
|
|
142
|
-
filter: (src) => {
|
|
143
|
-
const ext = path.extname(src).toLowerCase()
|
|
144
|
-
// Only copy files with extensions, not directories alone
|
|
145
|
-
if (fs.statSync(src).isDirectory()) {
|
|
146
|
-
return true // Allow directories in copying
|
|
147
|
-
}
|
|
148
|
-
// Ensure the file has a valid extension from the whitelist
|
|
149
|
-
return ext !== '' // Only copy files with extensions
|
|
150
|
-
},
|
|
151
|
-
})
|
|
152
|
-
console.log('Copied H5P template/assets to package')
|
|
153
|
-
} catch (error) {
|
|
154
|
-
console.warn('Error copying H5P assets:', error)
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// List of allowed extensions for H5P
|
|
158
|
-
const allowedExtensions = [
|
|
159
|
-
'json',
|
|
160
|
-
'png',
|
|
161
|
-
'jpg',
|
|
162
|
-
'jpeg',
|
|
163
|
-
'gif',
|
|
164
|
-
'bmp',
|
|
165
|
-
'tif',
|
|
166
|
-
'tiff',
|
|
167
|
-
'eot',
|
|
168
|
-
'ttf',
|
|
169
|
-
'woff',
|
|
170
|
-
'woff2',
|
|
171
|
-
'otf',
|
|
172
|
-
'webm',
|
|
173
|
-
'mp4',
|
|
174
|
-
'ogg',
|
|
175
|
-
'mp3',
|
|
176
|
-
'm4a',
|
|
177
|
-
'wav',
|
|
178
|
-
'txt',
|
|
179
|
-
'pdf',
|
|
180
|
-
'rtf',
|
|
181
|
-
'doc',
|
|
182
|
-
'docx',
|
|
183
|
-
'xls',
|
|
184
|
-
'xlsx',
|
|
185
|
-
'ppt',
|
|
186
|
-
'pptx',
|
|
187
|
-
'odt',
|
|
188
|
-
'ods',
|
|
189
|
-
'odp',
|
|
190
|
-
'csv',
|
|
191
|
-
'diff',
|
|
192
|
-
'patch',
|
|
193
|
-
'swf',
|
|
194
|
-
'md',
|
|
195
|
-
'textile',
|
|
196
|
-
'vtt',
|
|
197
|
-
'webvtt',
|
|
198
|
-
'gltf',
|
|
199
|
-
'glb',
|
|
200
|
-
'js',
|
|
201
|
-
'css',
|
|
202
|
-
'svg',
|
|
203
|
-
'xml',
|
|
204
|
-
]
|
|
205
|
-
|
|
206
|
-
// Copy user's content files with allowed extensions
|
|
207
|
-
if (fs.existsSync(argument.path)) {
|
|
208
|
-
try {
|
|
209
|
-
// Get all files to copy - only files, not directories
|
|
210
|
-
const getAllFiles = function (
|
|
211
|
-
dirPath: string,
|
|
212
|
-
arrayOfFiles: { source: string; target: string }[] = []
|
|
213
|
-
) {
|
|
214
|
-
const files = fs.readdirSync(dirPath)
|
|
215
|
-
|
|
216
|
-
files.forEach(function (file) {
|
|
217
|
-
const filePath = path.join(dirPath, file)
|
|
218
|
-
const stats = fs.statSync(filePath)
|
|
219
|
-
|
|
220
|
-
if (stats.isDirectory()) {
|
|
221
|
-
// Recurse into subdirectories
|
|
222
|
-
arrayOfFiles = getAllFiles(filePath, arrayOfFiles)
|
|
223
|
-
} else {
|
|
224
|
-
const ext = path.extname(file).toLowerCase().substring(1)
|
|
225
|
-
if (allowedExtensions.includes(ext)) {
|
|
226
|
-
// Use flat structure - put all files at root with prefixed names to avoid collisions
|
|
227
|
-
// This avoids directory whitelist issues
|
|
228
|
-
const flatFileName = path
|
|
229
|
-
.relative(argument.path, filePath)
|
|
230
|
-
.replace(/\//g, '_') // Replace slashes with underscores
|
|
231
|
-
.replace(/\\/g, '_') // Handle Windows paths too
|
|
232
|
-
|
|
233
|
-
arrayOfFiles.push({
|
|
234
|
-
source: filePath,
|
|
235
|
-
target: path.join(h5pRoot, flatFileName),
|
|
236
|
-
})
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
})
|
|
240
|
-
|
|
241
|
-
return arrayOfFiles
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
const filesToCopy = getAllFiles(argument.path)
|
|
245
|
-
|
|
246
|
-
// Copy each file to the root level (no directories)
|
|
247
|
-
for (const file of filesToCopy) {
|
|
248
|
-
await fs.copy(file.source, file.target)
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
console.log(`Copied ${filesToCopy.length} resource files to H5P package`)
|
|
252
|
-
} catch (error) {
|
|
253
|
-
console.warn('Error copying content files:', error)
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// Package as .h5p file
|
|
258
|
-
if (argument['h5p-zip'] !== false) {
|
|
259
|
-
// Default to creating .h5p file
|
|
260
|
-
const output = fs.createWriteStream(argument.output + '.h5p')
|
|
261
|
-
const archive = archiver('zip', {
|
|
262
|
-
zlib: { level: 9 },
|
|
263
|
-
})
|
|
264
|
-
|
|
265
|
-
output.on('close', function () {
|
|
266
|
-
console.log(archive.pointer() + ' total bytes')
|
|
267
|
-
console.log(
|
|
268
|
-
'H5P package created successfully: ' + argument.output + '.h5p'
|
|
269
|
-
)
|
|
270
|
-
})
|
|
271
|
-
|
|
272
|
-
archive.on('error', function (err) {
|
|
273
|
-
throw err
|
|
274
|
-
})
|
|
275
|
-
|
|
276
|
-
archive.pipe(output)
|
|
277
|
-
|
|
278
|
-
// Add all files from the h5pRoot directory to the archive
|
|
279
|
-
archive.directory(h5pRoot, false)
|
|
280
|
-
archive.finalize()
|
|
281
|
-
} else {
|
|
282
|
-
// Otherwise just copy the directory
|
|
283
|
-
await fs.copy(h5pRoot, argument.output)
|
|
284
|
-
console.log('H5P content created successfully at: ' + argument.output)
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
// Update the function signature to accept markdownContent
|
|
289
|
-
async function createSelfContainedHtml(indexPath, basePath, markdownContent) {
|
|
290
|
-
const cheerio = require('cheerio')
|
|
291
|
-
const fs = require('fs-extra')
|
|
292
|
-
const path = require('path')
|
|
293
|
-
const mime = require('mime-types')
|
|
294
|
-
|
|
295
|
-
// Read the index HTML file
|
|
296
|
-
const htmlContent = await fs.readFile(indexPath, 'utf8')
|
|
297
|
-
const $ = cheerio.load(htmlContent)
|
|
298
|
-
|
|
299
|
-
// Process and inline JavaScript files
|
|
300
|
-
$('script[src]').each(function () {
|
|
301
|
-
const src = $(this).attr('src')
|
|
302
|
-
if (
|
|
303
|
-
src.startsWith('http:') ||
|
|
304
|
-
src.startsWith('https:') ||
|
|
305
|
-
src.startsWith('//')
|
|
306
|
-
) {
|
|
307
|
-
// Skip external scripts
|
|
308
|
-
return
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
try {
|
|
312
|
-
const scriptPath = path.resolve(path.dirname(indexPath), src)
|
|
313
|
-
const scriptContent = fs.readFileSync(scriptPath, 'utf8')
|
|
314
|
-
$(this).removeAttr('src').text(scriptContent)
|
|
315
|
-
console.log(`Inlined script: ${src}`)
|
|
316
|
-
} catch (error) {
|
|
317
|
-
console.warn(`Could not inline script ${src}:`, error.message)
|
|
318
|
-
}
|
|
319
|
-
})
|
|
320
|
-
|
|
321
|
-
// Process and inline CSS files
|
|
322
|
-
$('link[rel="stylesheet"]').each(function () {
|
|
323
|
-
const href = $(this).attr('href')
|
|
324
|
-
if (
|
|
325
|
-
href.startsWith('http:') ||
|
|
326
|
-
href.startsWith('https:') ||
|
|
327
|
-
href.startsWith('//')
|
|
328
|
-
) {
|
|
329
|
-
// Skip external stylesheets
|
|
330
|
-
return
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
try {
|
|
334
|
-
const cssPath = path.resolve(path.dirname(indexPath), href)
|
|
335
|
-
const cssContent = fs.readFileSync(cssPath, 'utf8')
|
|
336
|
-
$(this).replaceWith(`<style>${cssContent}</style>`)
|
|
337
|
-
console.log(`Inlined CSS: ${href}`)
|
|
338
|
-
} catch (error) {
|
|
339
|
-
console.warn(`Could not inline CSS ${href}:`, error.message)
|
|
340
|
-
}
|
|
341
|
-
})
|
|
342
|
-
|
|
343
|
-
// Process and inline images (convert to data URLs)
|
|
344
|
-
$('img[src]').each(function () {
|
|
345
|
-
const src = $(this).attr('src')
|
|
346
|
-
if (
|
|
347
|
-
src.startsWith('data:') ||
|
|
348
|
-
src.startsWith('http:') ||
|
|
349
|
-
src.startsWith('https:') ||
|
|
350
|
-
src.startsWith('//')
|
|
351
|
-
) {
|
|
352
|
-
// Skip already inlined or external images
|
|
353
|
-
return
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
try {
|
|
357
|
-
const imgPath = path.resolve(path.dirname(indexPath), src)
|
|
358
|
-
const imgBuffer = fs.readFileSync(imgPath)
|
|
359
|
-
const mimeType = mime.lookup(imgPath) || 'application/octet-stream'
|
|
360
|
-
const dataUrl = `data:${mimeType};base64,${imgBuffer.toString('base64')}`
|
|
361
|
-
$(this).attr('src', dataUrl)
|
|
362
|
-
console.log(`Inlined image: ${src}`)
|
|
363
|
-
} catch (error) {
|
|
364
|
-
console.warn(`Could not inline image ${src}:`, error.message)
|
|
365
|
-
}
|
|
366
|
-
})
|
|
367
|
-
|
|
368
|
-
// Inject the markdown content directly
|
|
369
|
-
$('#container').append(`
|
|
370
|
-
<div id="embedded-markdown" style="display:none;">
|
|
371
|
-
${markdownContent.replace(/</g, '<').replace(/>/g, '>')}
|
|
372
|
-
</div>
|
|
373
|
-
`)
|
|
374
|
-
|
|
375
|
-
// Add a script to process the embedded markdown on page load
|
|
376
|
-
$('body').append(`
|
|
377
|
-
<script>
|
|
378
|
-
document.addEventListener('DOMContentLoaded', function() {
|
|
379
|
-
if (window.LIA && typeof window.LIA.loadMarkdown === 'function') {
|
|
380
|
-
const markdown = document.getElementById('embedded-markdown').innerHTML
|
|
381
|
-
.replace(/</g, '<')
|
|
382
|
-
.replace(/>/g, '>');
|
|
383
|
-
window.LIA.loadMarkdown(markdown);
|
|
384
|
-
}
|
|
385
|
-
});
|
|
386
|
-
</script>
|
|
387
|
-
`)
|
|
388
|
-
|
|
389
|
-
return $.html()
|
|
390
|
-
}
|