@basthon/gui-base 0.62.20 → 0.62.22
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/lib/main.js +29 -40
- package/package.json +12 -14
package/lib/main.js
CHANGED
|
@@ -6,7 +6,6 @@ import { KernelLoader } from "@basthon/kernel-loader";
|
|
|
6
6
|
*/
|
|
7
7
|
export class GUIBase {
|
|
8
8
|
constructor(options) {
|
|
9
|
-
var _a;
|
|
10
9
|
this._loaded = new PromiseDelegate();
|
|
11
10
|
this._maxCheckpoints = 10;
|
|
12
11
|
this._contentFilename = "content.txt";
|
|
@@ -14,7 +13,7 @@ export class GUIBase {
|
|
|
14
13
|
this._extensions = new Map();
|
|
15
14
|
/* console errors redirected to notification system */
|
|
16
15
|
this._console_error = console.error;
|
|
17
|
-
this._language =
|
|
16
|
+
this._language = options?.kernelOptions?.language;
|
|
18
17
|
this._loader = new KernelLoader(options.kernelOptions);
|
|
19
18
|
// loading Basthon (errors are fatal)
|
|
20
19
|
this._loader.showLoader("Chargement de Basthon...", false, false);
|
|
@@ -84,14 +83,19 @@ export class GUIBase {
|
|
|
84
83
|
* The error notification system.
|
|
85
84
|
*/
|
|
86
85
|
notifyError(error) {
|
|
87
|
-
var _a, _b;
|
|
88
86
|
this._console_error(error);
|
|
89
87
|
let message = error.message;
|
|
90
88
|
if (message == null)
|
|
91
|
-
message =
|
|
89
|
+
message = error?.reason?.message;
|
|
92
90
|
if (message == null)
|
|
93
91
|
message = error.toString();
|
|
94
|
-
|
|
92
|
+
// avoid html/js injection on errors
|
|
93
|
+
const encodeHTMLEntities = (text) => {
|
|
94
|
+
var textArea = document.createElement("textarea");
|
|
95
|
+
textArea.innerText = text;
|
|
96
|
+
return textArea.innerHTML;
|
|
97
|
+
};
|
|
98
|
+
message = encodeHTMLEntities(message).split("\n").join("<br>");
|
|
95
99
|
this.error("Erreur", `Erreur : ${message}`);
|
|
96
100
|
// In case of error, force loader hiding.
|
|
97
101
|
try {
|
|
@@ -125,7 +129,6 @@ export class GUIBase {
|
|
|
125
129
|
* Loading the content from query string (ipynb=/script= or from=).
|
|
126
130
|
*/
|
|
127
131
|
async loadFromQS(key) {
|
|
128
|
-
var _a;
|
|
129
132
|
const url = new URL(window.location.href);
|
|
130
133
|
const from_key = "from";
|
|
131
134
|
let content = null;
|
|
@@ -156,7 +159,7 @@ export class GUIBase {
|
|
|
156
159
|
content = await response.text();
|
|
157
160
|
}
|
|
158
161
|
catch (error) {
|
|
159
|
-
throw new Error(`Le chargement de ${fileURL} a échoué : ${
|
|
162
|
+
throw new Error(`Le chargement de ${fileURL} a échoué : ${error?.message ?? error.toString()}`);
|
|
160
163
|
}
|
|
161
164
|
}
|
|
162
165
|
}
|
|
@@ -169,10 +172,9 @@ export class GUIBase {
|
|
|
169
172
|
* (call submited callback).
|
|
170
173
|
*/
|
|
171
174
|
async _loadExtensions() {
|
|
172
|
-
var _a, _b;
|
|
173
175
|
/* get requested extensions from URL */
|
|
174
176
|
const url = new URL(window.location.href);
|
|
175
|
-
const extensions =
|
|
177
|
+
const extensions = url.searchParams.get("extensions")?.split(",") ?? [];
|
|
176
178
|
// call callbacks for requested extensions
|
|
177
179
|
const promises = [];
|
|
178
180
|
for (const ext of extensions) {
|
|
@@ -212,8 +214,7 @@ export class GUIBase {
|
|
|
212
214
|
* Get state from strorage.
|
|
213
215
|
*/
|
|
214
216
|
async getState(state, def) {
|
|
215
|
-
|
|
216
|
-
return (_a = (await this._stateStorage.get(state))) !== null && _a !== void 0 ? _a : def;
|
|
217
|
+
return (await this._stateStorage.get(state)) ?? def;
|
|
217
218
|
}
|
|
218
219
|
/**
|
|
219
220
|
* Set state in storage.
|
|
@@ -235,14 +236,13 @@ export class GUIBase {
|
|
|
235
236
|
* Load content from local forage.
|
|
236
237
|
*/
|
|
237
238
|
async loadFromStorage(setContent = true) {
|
|
238
|
-
var _a;
|
|
239
239
|
const approved = await this.lastBackupValid();
|
|
240
240
|
let content = null;
|
|
241
241
|
if (approved == null) {
|
|
242
242
|
content = null;
|
|
243
243
|
}
|
|
244
244
|
else if (approved) {
|
|
245
|
-
content = (await
|
|
245
|
+
content = (await this._checkpoints?.getLast());
|
|
246
246
|
}
|
|
247
247
|
else {
|
|
248
248
|
const promise = new PromiseDelegate();
|
|
@@ -261,28 +261,24 @@ export class GUIBase {
|
|
|
261
261
|
* Tag last backup as "approved".
|
|
262
262
|
*/
|
|
263
263
|
async validateBackup() {
|
|
264
|
-
|
|
265
|
-
await ((_a = this._checkpoints) === null || _a === void 0 ? void 0 : _a.tagLast("approved"));
|
|
264
|
+
await this._checkpoints?.tagLast("approved");
|
|
266
265
|
}
|
|
267
266
|
/**
|
|
268
267
|
* Is last backup tagged as "approved"?
|
|
269
268
|
*/
|
|
270
269
|
async lastBackupValid() {
|
|
271
|
-
|
|
272
|
-
return await ((_a = this._checkpoints) === null || _a === void 0 ? void 0 : _a.lastHasTag("approved"));
|
|
270
|
+
return await this._checkpoints?.lastHasTag("approved");
|
|
273
271
|
}
|
|
274
272
|
/**
|
|
275
273
|
* Select a checkpoint to load in the script.
|
|
276
274
|
*/
|
|
277
275
|
async selectCheckpoint() {
|
|
278
|
-
|
|
279
|
-
const times = await ((_a = this._checkpoints) === null || _a === void 0 ? void 0 : _a.times());
|
|
276
|
+
const times = await this._checkpoints?.times();
|
|
280
277
|
const promise = new PromiseDelegate();
|
|
281
|
-
const choices = times
|
|
278
|
+
const choices = times?.map((t, i) => ({
|
|
282
279
|
text: CheckpointsManager.toHumanDate(parseInt(t, 10)),
|
|
283
280
|
handler: async () => {
|
|
284
|
-
|
|
285
|
-
promise.resolve((_b = (await ((_a = this._checkpoints) === null || _a === void 0 ? void 0 : _a.getIndex(i)))) !== null && _b !== void 0 ? _b : null);
|
|
281
|
+
promise.resolve((await this._checkpoints?.getIndex(i)) ?? null);
|
|
286
282
|
},
|
|
287
283
|
}));
|
|
288
284
|
if (choices == null)
|
|
@@ -302,25 +298,23 @@ export class GUIBase {
|
|
|
302
298
|
* Backup to checkpoints.
|
|
303
299
|
*/
|
|
304
300
|
async backup(approved = true) {
|
|
305
|
-
|
|
306
|
-
return await ((_a = this._checkpoints) === null || _a === void 0 ? void 0 : _a.push(this.content(), approved ? ["approved"] : []));
|
|
301
|
+
return await this._checkpoints?.push(this.content(), approved ? ["approved"] : []);
|
|
307
302
|
}
|
|
308
303
|
/**
|
|
309
304
|
* Internal GUI init.
|
|
310
305
|
* It calls setupUI then loadInitialContent.
|
|
311
306
|
*/
|
|
312
307
|
async _init(options = null) {
|
|
313
|
-
var _a;
|
|
314
308
|
/* all errors redirected to notification system */
|
|
315
309
|
const onerror = this.notifyError.bind(this);
|
|
316
310
|
window.addEventListener("error", onerror);
|
|
317
311
|
window.addEventListener("unhandledrejection", onerror);
|
|
318
312
|
console.error = (message) => onerror(new Error(message));
|
|
319
313
|
await this._loadExtensions();
|
|
320
|
-
await
|
|
314
|
+
await this._checkpoints?.ready();
|
|
321
315
|
await this.setupUI(options);
|
|
322
316
|
await this.loadInitialContent(options);
|
|
323
|
-
await this.kernelLoader.
|
|
317
|
+
await this.kernelLoader.kernelStarted();
|
|
324
318
|
const init = this.initCaller.bind(this);
|
|
325
319
|
// loading aux files from URL
|
|
326
320
|
await init(this.loadURLAux.bind(this), "Chargement des fichiers auxiliaires...", true);
|
|
@@ -355,10 +349,8 @@ export class GUIBase {
|
|
|
355
349
|
* Restart the kernel.
|
|
356
350
|
*/
|
|
357
351
|
kernelRestart() {
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
throw new Error("pending input");
|
|
361
|
-
(_b = this.kernelSafe) === null || _b === void 0 ? void 0 : _b.restart();
|
|
352
|
+
this.kernelSafe?.resolvePendingInput();
|
|
353
|
+
this.kernelSafe?.restart();
|
|
362
354
|
}
|
|
363
355
|
/**
|
|
364
356
|
* Load ressources from URL (common part to files and modules).
|
|
@@ -370,7 +362,6 @@ export class GUIBase {
|
|
|
370
362
|
fileURL = decodeURIComponent(fileURL);
|
|
371
363
|
const filename = fileURL.split("/").pop() || "";
|
|
372
364
|
promises.push((async () => {
|
|
373
|
-
var _a;
|
|
374
365
|
let data;
|
|
375
366
|
try {
|
|
376
367
|
const response = await fetch(fileURL);
|
|
@@ -380,7 +371,7 @@ export class GUIBase {
|
|
|
380
371
|
await put(filename, data);
|
|
381
372
|
}
|
|
382
373
|
catch (error) {
|
|
383
|
-
throw new Error(`Impossible de charger le fichier ${filename} : ${
|
|
374
|
+
throw new Error(`Impossible de charger le fichier ${filename} : ${error?.message ?? error.toString()}`);
|
|
384
375
|
}
|
|
385
376
|
})());
|
|
386
377
|
}
|
|
@@ -394,9 +385,8 @@ export class GUIBase {
|
|
|
394
385
|
const reader = new FileReader();
|
|
395
386
|
reader.readAsArrayBuffer(file);
|
|
396
387
|
reader.onload = async (event) => {
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
this.info(`Fichier utilisable depuis ${(_b = this.kernel) === null || _b === void 0 ? void 0 : _b.languageName()}`, `${file.name} est maintenant utilisable depuis ${(_c = this.kernel) === null || _c === void 0 ? void 0 : _c.languageName()}`);
|
|
388
|
+
await this.kernelSafe?.putRessource(file.name, reader.result);
|
|
389
|
+
this.info(`Fichier utilisable depuis ${this.kernel?.languageName()}`, `${file.name} est maintenant utilisable depuis ${this.kernel?.languageName()}`);
|
|
400
390
|
resolve();
|
|
401
391
|
};
|
|
402
392
|
reader.onerror = reject;
|
|
@@ -440,7 +430,7 @@ export class GUIBase {
|
|
|
440
430
|
return;
|
|
441
431
|
for (let file of input.files) {
|
|
442
432
|
const ext = file.name.split(".").pop();
|
|
443
|
-
const callback = callbacks[ext
|
|
433
|
+
const callback = callbacks[ext ?? ""];
|
|
444
434
|
if (callback != null) {
|
|
445
435
|
await callback(file);
|
|
446
436
|
}
|
|
@@ -510,8 +500,7 @@ Un lien permanant vers le contenu actuel a été créé.
|
|
|
510
500
|
const reader = new FileReader();
|
|
511
501
|
reader.readAsText(file);
|
|
512
502
|
reader.onload = (event) => {
|
|
513
|
-
|
|
514
|
-
this.setContent((_a = event === null || event === void 0 ? void 0 : event.target) === null || _a === void 0 ? void 0 : _a.result);
|
|
503
|
+
this.setContent(event?.target?.result);
|
|
515
504
|
resolve();
|
|
516
505
|
};
|
|
517
506
|
reader.onerror = reject;
|
|
@@ -524,7 +513,7 @@ Un lien permanant vers le contenu actuel a été créé.
|
|
|
524
513
|
this.backup();
|
|
525
514
|
const content = this.content().replace(/\r\n|\r|\n/g, "\r\n"); // To retain the Line breaks.
|
|
526
515
|
let blob = new Blob([content], { type: "text/plain" });
|
|
527
|
-
GUIBase.openURL(window.URL.createObjectURL(blob), filename
|
|
516
|
+
GUIBase.openURL(window.URL.createObjectURL(blob), filename ?? this._contentFilename);
|
|
528
517
|
}
|
|
529
518
|
/**
|
|
530
519
|
* Compress a string to another string (URL safe).
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@basthon/gui-base",
|
|
3
|
-
"version": "0.62.
|
|
3
|
+
"version": "0.62.22",
|
|
4
4
|
"description": "Basthon - Base GUI",
|
|
5
5
|
"homepage": "https://basthon.fr",
|
|
6
6
|
"bugs": {
|
|
7
|
-
"url": "https://
|
|
7
|
+
"url": "https://forge.apps.education.fr/basthon/basthon-kernel/issues"
|
|
8
8
|
},
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
11
|
-
"url": "https://
|
|
11
|
+
"url": "https://forge.apps.education.fr/basthon/basthon-kernel.git"
|
|
12
12
|
},
|
|
13
13
|
"license": "GPL-3.0-or-later",
|
|
14
14
|
"author": "Romain Casati",
|
|
@@ -21,25 +21,23 @@
|
|
|
21
21
|
"lib"
|
|
22
22
|
],
|
|
23
23
|
"scripts": {
|
|
24
|
-
"build": "
|
|
24
|
+
"build": "tsc",
|
|
25
25
|
"clean": "rm -rf lib/"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@basthon/checkpoints": "0.62.
|
|
29
|
-
"@basthon/kernel-base": "0.62.
|
|
30
|
-
"@basthon/kernel-loader": "0.62.
|
|
31
|
-
"js-base64": "^3.7.
|
|
32
|
-
"pako": "^2.0
|
|
28
|
+
"@basthon/checkpoints": "0.62.22",
|
|
29
|
+
"@basthon/kernel-base": "0.62.22",
|
|
30
|
+
"@basthon/kernel-loader": "0.62.22",
|
|
31
|
+
"js-base64": "^3.7.7",
|
|
32
|
+
"pako": "^2.1.0",
|
|
33
33
|
"promise-delegate": "^1.0.1"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@types/pako": "^
|
|
37
|
-
"
|
|
38
|
-
"gulp-typescript": "^6.0.0-alpha.1",
|
|
39
|
-
"typescript": "~4.4.4"
|
|
36
|
+
"@types/pako": "^2.0.3",
|
|
37
|
+
"typescript": "~5.4.5"
|
|
40
38
|
},
|
|
41
39
|
"publishConfig": {
|
|
42
40
|
"access": "public"
|
|
43
41
|
},
|
|
44
|
-
"gitHead": "
|
|
42
|
+
"gitHead": "1dd6225a7caf14cbee203687cac611495f5b18d4"
|
|
45
43
|
}
|