@es-joy/jsoe 0.16.0 → 0.17.0
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/.ncurc.cjs +4 -5
- package/CHANGES.md +4 -0
- package/README.md +27 -3
- package/badges/licenses-badge.svg +1 -0
- package/dist/formatAndTypeChoices.d.ts +39 -19
- package/dist/formatAndTypeChoices.d.ts.map +1 -1
- package/dist/formats/indexedDBKey.d.ts +1 -1
- package/dist/formats/indexedDBKey.d.ts.map +1 -1
- package/dist/formats/json.d.ts +1 -1
- package/dist/formats/json.d.ts.map +1 -1
- package/dist/formats/schema.d.ts +11 -0
- package/dist/formats/schema.d.ts.map +1 -0
- package/dist/formats/structuredCloning.d.ts +11 -13
- package/dist/formats/structuredCloning.d.ts.map +1 -1
- package/dist/formats.d.ts +86 -25
- package/dist/formats.d.ts.map +1 -1
- package/dist/fundamentalTypes/BooleanObjectType.d.ts +1 -1
- package/dist/fundamentalTypes/BooleanObjectType.d.ts.map +1 -1
- package/dist/fundamentalTypes/NumberObjectType.d.ts +1 -1
- package/dist/fundamentalTypes/NumberObjectType.d.ts.map +1 -1
- package/dist/fundamentalTypes/StringObjectType.d.ts +1 -1
- package/dist/fundamentalTypes/StringObjectType.d.ts.map +1 -1
- package/dist/fundamentalTypes/arrayReferenceType.d.ts +1 -1
- package/dist/fundamentalTypes/arrayType.d.ts +3 -3
- package/dist/fundamentalTypes/arrayType.d.ts.map +1 -1
- package/dist/fundamentalTypes/bigintObjectType.d.ts +6 -0
- package/dist/fundamentalTypes/bigintObjectType.d.ts.map +1 -0
- package/dist/fundamentalTypes/bigintType.d.ts +1 -1
- package/dist/fundamentalTypes/bigintType.d.ts.map +1 -1
- package/dist/fundamentalTypes/blobType.d.ts +1 -1
- package/dist/fundamentalTypes/blobType.d.ts.map +1 -1
- package/dist/fundamentalTypes/booleanType.d.ts +8 -0
- package/dist/fundamentalTypes/booleanType.d.ts.map +1 -0
- package/dist/fundamentalTypes/catchType.d.ts +6 -0
- package/dist/fundamentalTypes/catchType.d.ts.map +1 -0
- package/dist/fundamentalTypes/dateType.d.ts +4 -4
- package/dist/fundamentalTypes/dateType.d.ts.map +1 -1
- package/dist/fundamentalTypes/domexceptionType.d.ts +1 -1
- package/dist/fundamentalTypes/domexceptionType.d.ts.map +1 -1
- package/dist/fundamentalTypes/enumType.d.ts +6 -0
- package/dist/fundamentalTypes/enumType.d.ts.map +1 -0
- package/dist/fundamentalTypes/errorType.d.ts +1 -1
- package/dist/fundamentalTypes/errorType.d.ts.map +1 -1
- package/dist/fundamentalTypes/fileType.d.ts +1 -1
- package/dist/fundamentalTypes/fileType.d.ts.map +1 -1
- package/dist/fundamentalTypes/filelistType.d.ts +1 -1
- package/dist/fundamentalTypes/filelistType.d.ts.map +1 -1
- package/dist/fundamentalTypes/functionType.d.ts +6 -0
- package/dist/fundamentalTypes/functionType.d.ts.map +1 -0
- package/dist/fundamentalTypes/literalType.d.ts +6 -0
- package/dist/fundamentalTypes/literalType.d.ts.map +1 -0
- package/dist/fundamentalTypes/mapType.d.ts +1 -1
- package/dist/fundamentalTypes/mapType.d.ts.map +1 -1
- package/dist/fundamentalTypes/nanType.d.ts +6 -0
- package/dist/fundamentalTypes/nanType.d.ts.map +1 -0
- package/dist/fundamentalTypes/nativeEnumType.d.ts +6 -0
- package/dist/fundamentalTypes/nativeEnumType.d.ts.map +1 -0
- package/dist/fundamentalTypes/neverType.d.ts +6 -0
- package/dist/fundamentalTypes/neverType.d.ts.map +1 -0
- package/dist/fundamentalTypes/noneditableType.d.ts +1 -1
- package/dist/fundamentalTypes/noneditableType.d.ts.map +1 -1
- package/dist/fundamentalTypes/nullType.d.ts +1 -1
- package/dist/fundamentalTypes/nullType.d.ts.map +1 -1
- package/dist/fundamentalTypes/numberType.d.ts +1 -1
- package/dist/fundamentalTypes/numberType.d.ts.map +1 -1
- package/dist/fundamentalTypes/objectReferenceType.d.ts +1 -1
- package/dist/fundamentalTypes/objectType.d.ts +1 -1
- package/dist/fundamentalTypes/objectType.d.ts.map +1 -1
- package/dist/fundamentalTypes/promiseType.d.ts +6 -0
- package/dist/fundamentalTypes/promiseType.d.ts.map +1 -0
- package/dist/fundamentalTypes/recordType.d.ts +6 -0
- package/dist/fundamentalTypes/recordType.d.ts.map +1 -0
- package/dist/fundamentalTypes/regexpType.d.ts +1 -1
- package/dist/fundamentalTypes/regexpType.d.ts.map +1 -1
- package/dist/fundamentalTypes/setType.d.ts +1 -1
- package/dist/fundamentalTypes/setType.d.ts.map +1 -1
- package/dist/fundamentalTypes/sparseUndefinedType.d.ts +1 -1
- package/dist/fundamentalTypes/sparseUndefinedType.d.ts.map +1 -1
- package/dist/fundamentalTypes/stringType.d.ts +1 -1
- package/dist/fundamentalTypes/stringType.d.ts.map +1 -1
- package/dist/fundamentalTypes/symbolType.d.ts +8 -0
- package/dist/fundamentalTypes/symbolType.d.ts.map +1 -0
- package/dist/fundamentalTypes/tupleType.d.ts +6 -0
- package/dist/fundamentalTypes/tupleType.d.ts.map +1 -0
- package/dist/fundamentalTypes/undefinedType.d.ts +1 -1
- package/dist/fundamentalTypes/undefinedType.d.ts.map +1 -1
- package/dist/fundamentalTypes/voidType.d.ts +6 -0
- package/dist/fundamentalTypes/voidType.d.ts.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9660 -1586
- package/dist/subTypes/blobHTMLType.d.ts.map +1 -1
- package/dist/subTypes/falseType.d.ts +1 -1
- package/dist/subTypes/trueType.d.ts +1 -1
- package/dist/superTypes/SpecialNumberType.d.ts +1 -1
- package/dist/superTypes/SpecialRealNumberType.d.ts +1 -1
- package/dist/superTypes/SpecialRealNumberType.d.ts.map +1 -1
- package/dist/superTypes/buffersourceType.d.ts +1 -1
- package/dist/superTypes/buffersourceType.d.ts.map +1 -1
- package/dist/superTypes/dommatrixType.d.ts +1 -1
- package/dist/superTypes/dommatrixType.d.ts.map +1 -1
- package/dist/superTypes/dompointType.d.ts +1 -1
- package/dist/superTypes/dompointType.d.ts.map +1 -1
- package/dist/superTypes/domrectType.d.ts +1 -1
- package/dist/superTypes/domrectType.d.ts.map +1 -1
- package/dist/superTypes/errorsSpecialType.d.ts +1 -1
- package/dist/superTypes/errorsSpecialType.d.ts.map +1 -1
- package/dist/typeChoices.d.ts +33 -16
- package/dist/typeChoices.d.ts.map +1 -1
- package/dist/types.d.ts +161 -157
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/dialogs.d.ts +3 -3
- package/dist/utils/dialogs.d.ts.map +1 -1
- package/dist/utils/jsonPointer.d.ts.map +1 -1
- package/dist/utils/media.d.ts.map +1 -1
- package/dist/utils/objects.d.ts +16 -0
- package/dist/utils/objects.d.ts.map +1 -0
- package/dist/utils/types.d.ts +1 -1
- package/dist/utils/types.d.ts.map +1 -1
- package/dist/vendor-imports.d.ts +1 -1
- package/eslint.config.js +74 -0
- package/licenseInfo.json +4 -0
- package/package.json +33 -42
- package/rollup.config.js +15 -0
- package/src/formatAndTypeChoices.js +68 -54
- package/src/formats/indexedDBKey.js +9 -4
- package/src/formats/json.js +7 -4
- package/src/formats/schema.js +772 -0
- package/src/formats/structuredCloning.js +187 -86
- package/src/formats.js +61 -26
- package/src/fundamentalTypes/BooleanObjectType.js +18 -6
- package/src/fundamentalTypes/NumberObjectType.js +18 -5
- package/src/fundamentalTypes/StringObjectType.js +20 -8
- package/src/fundamentalTypes/arrayType.js +1241 -533
- package/src/fundamentalTypes/bigintObjectType.js +64 -0
- package/src/fundamentalTypes/bigintType.js +31 -5
- package/src/fundamentalTypes/blobType.js +201 -190
- package/src/fundamentalTypes/booleanType.js +63 -0
- package/src/fundamentalTypes/catchType.js +140 -0
- package/src/fundamentalTypes/dateType.js +57 -19
- package/src/fundamentalTypes/domexceptionType.js +61 -63
- package/src/fundamentalTypes/enumType.js +52 -0
- package/src/fundamentalTypes/errorType.js +20 -7
- package/src/fundamentalTypes/fileType.js +195 -189
- package/src/fundamentalTypes/filelistType.js +4 -0
- package/src/fundamentalTypes/functionType.js +150 -0
- package/src/fundamentalTypes/literalType.js +81 -0
- package/src/fundamentalTypes/mapType.js +4 -0
- package/src/fundamentalTypes/nanType.js +41 -0
- package/src/fundamentalTypes/nativeEnumType.js +155 -0
- package/src/fundamentalTypes/neverType.js +44 -0
- package/src/fundamentalTypes/noneditableType.js +19 -5
- package/src/fundamentalTypes/nullType.js +16 -6
- package/src/fundamentalTypes/numberType.js +49 -6
- package/src/fundamentalTypes/objectType.js +10 -2
- package/src/fundamentalTypes/promiseType.js +60 -0
- package/src/fundamentalTypes/recordType.js +42 -0
- package/src/fundamentalTypes/regexpType.js +51 -33
- package/src/fundamentalTypes/setType.js +4 -0
- package/src/fundamentalTypes/sparseUndefinedType.js +3 -0
- package/src/fundamentalTypes/stringType.js +254 -6
- package/src/fundamentalTypes/symbolType.js +81 -0
- package/src/fundamentalTypes/tupleType.js +39 -0
- package/src/fundamentalTypes/undefinedType.js +14 -4
- package/src/fundamentalTypes/voidType.js +48 -0
- package/src/jsoe.css +37 -3
- package/src/subTypes/blobHTMLType.js +33 -24
- package/src/superTypes/SpecialRealNumberType.js +22 -6
- package/src/superTypes/buffersourceType.js +86 -30
- package/src/superTypes/dommatrixType.js +24 -7
- package/src/superTypes/dompointType.js +27 -7
- package/src/superTypes/domrectType.js +33 -7
- package/src/superTypes/errorsSpecialType.js +30 -14
- package/src/typeChoices.js +115 -44
- package/src/types.js +129 -45
- package/src/utils/FileList.js +3 -3
- package/src/utils/dialogs.js +6 -8
- package/src/utils/objects.js +22 -0
- package/src/vendor-imports.js +1 -1
- package/tsconfig.json +2 -2
- package/vendor/jamilih/dist/jml-es.js +23 -6
- package/vendor/typeson-registry/dist/index.js +77 -47
- package/vendor/zod/lib/index.mjs +4236 -0
- package/vendor/zodex/dist/esm/dezerialize.d.ts +26 -0
- package/vendor/zodex/dist/esm/dezerialize.js +393 -0
- package/vendor/zodex/dist/esm/index.d.ts +9 -0
- package/vendor/zodex/dist/esm/index.js +4 -0
- package/vendor/zodex/dist/esm/infer.d.ts +29 -0
- package/vendor/zodex/dist/esm/infer.js +1 -0
- package/vendor/zodex/dist/esm/package.json +1 -0
- package/vendor/zodex/dist/esm/types.d.ts +201 -0
- package/vendor/zodex/dist/esm/types.js +13 -0
- package/vendor/zodex/dist/esm/ui.d.ts +23 -0
- package/vendor/zodex/dist/esm/ui.js +10 -0
- package/vendor/zodex/dist/esm/zerialize.d.ts +50 -0
- package/vendor/zodex/dist/esm/zerialize.js +417 -0
- package/vendor/zodex/dist/esm/zod-types.d.ts +11 -0
- package/vendor/zodex/dist/esm/zod-types.js +1 -0
- package/.eslintignore +0 -13
- package/.eslintrc.cjs +0 -145
- package/.nyc_output/out.json +0 -117370
- package/cypress.config.ts +0 -15
- package/demo/index-instrumented.html +0 -29
- package/demo/index-instrumented.js +0 -644
- package/demo/index.html +0 -29
- package/demo/index.js +0 -215
- package/src/formats/schemaAndArbitrary.js +0 -20
- package/src/formats/schemaOnly.js +0 -539
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import {hasConstructorOf} from '../vendor-imports.js';
|
|
2
|
+
import {$e} from '../utils/templateUtils.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @type {import('../types.js').TypeObject}
|
|
6
|
+
*/
|
|
7
|
+
const bigintObjectType = {
|
|
8
|
+
option: ['BigInt Object'],
|
|
9
|
+
stringRegex: new RegExp(
|
|
10
|
+
'^BigIntObject' +
|
|
11
|
+
'-?' + // Optional negative sign.
|
|
12
|
+
// How many digits?
|
|
13
|
+
'[0-9]{1,}' +
|
|
14
|
+
'n' +
|
|
15
|
+
'$', // No trailing content.
|
|
16
|
+
'u'
|
|
17
|
+
),
|
|
18
|
+
valueMatch (x) {
|
|
19
|
+
return typeof x === 'object' && hasConstructorOf(x, BigInt);
|
|
20
|
+
},
|
|
21
|
+
toValue (s) {
|
|
22
|
+
return {value: new Object(BigInt(s.slice(12, -1)))};
|
|
23
|
+
},
|
|
24
|
+
getInput ({root}) {
|
|
25
|
+
return /** @type {HTMLInputElement} */ ($e(root, 'input'));
|
|
26
|
+
},
|
|
27
|
+
setValue ({root, value}) {
|
|
28
|
+
this.getInput({root}).value = String(value);
|
|
29
|
+
},
|
|
30
|
+
validate ({root}) {
|
|
31
|
+
const val = this.getInput({root}).value;
|
|
32
|
+
return {
|
|
33
|
+
message: 'Not a valid BigInt',
|
|
34
|
+
valid: Boolean(val && (/^-?(\d+)$/u).test(val))
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
getValue ({root}) {
|
|
38
|
+
return new Object(BigInt(this.getInput({root}).value));
|
|
39
|
+
},
|
|
40
|
+
/* schema:
|
|
41
|
+
viewSchemaUI () {
|
|
42
|
+
// Todo?
|
|
43
|
+
},
|
|
44
|
+
*/
|
|
45
|
+
viewUI ({value, specificSchemaObject}) {
|
|
46
|
+
return ['i', {
|
|
47
|
+
dataset: {type: 'bigintObject'},
|
|
48
|
+
title: specificSchemaObject?.description ?? '(a BigInt Object)'
|
|
49
|
+
}, [`${String(value)}n`]];
|
|
50
|
+
},
|
|
51
|
+
editUI ({typeNamespace, specificSchemaObject, value = ''}) {
|
|
52
|
+
return ['div', {
|
|
53
|
+
dataset: {type: 'bigintObject'},
|
|
54
|
+
title: specificSchemaObject?.description ?? 'BigInt object'
|
|
55
|
+
}, [
|
|
56
|
+
['input', {
|
|
57
|
+
name: `${typeNamespace}-bigintObject`, type: 'number', step: '1',
|
|
58
|
+
value
|
|
59
|
+
}]
|
|
60
|
+
]];
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export default bigintObjectType;
|
|
@@ -14,6 +14,9 @@ const bigintType = {
|
|
|
14
14
|
'$', // No trailing content.
|
|
15
15
|
'u'
|
|
16
16
|
),
|
|
17
|
+
valueMatch (x) {
|
|
18
|
+
return typeof x === 'bigint';
|
|
19
|
+
},
|
|
17
20
|
toValue (s) {
|
|
18
21
|
return {value: BigInt(s.slice(0, -1))};
|
|
19
22
|
},
|
|
@@ -38,13 +41,36 @@ const bigintType = {
|
|
|
38
41
|
// Todo?
|
|
39
42
|
},
|
|
40
43
|
*/
|
|
41
|
-
viewUI ({value}) {
|
|
42
|
-
return ['i', {
|
|
44
|
+
viewUI ({value, specificSchemaObject}) {
|
|
45
|
+
return ['i', {
|
|
46
|
+
dataset: {type: 'bigint'},
|
|
47
|
+
title: specificSchemaObject?.description ?? '(a BigInt)'
|
|
48
|
+
}, [
|
|
49
|
+
`${String(value)}n`
|
|
50
|
+
]];
|
|
43
51
|
},
|
|
44
|
-
editUI ({typeNamespace, value
|
|
45
|
-
|
|
52
|
+
editUI ({typeNamespace, specificSchemaObject, value}) {
|
|
53
|
+
const bigintSchemaObject = /** @type {import('zodex').SzBigInt} */ (
|
|
54
|
+
specificSchemaObject
|
|
55
|
+
);
|
|
56
|
+
return ['div', {
|
|
57
|
+
dataset: {type: 'bigint'},
|
|
58
|
+
title: specificSchemaObject?.description ?? 'BigInt'
|
|
59
|
+
}, [
|
|
46
60
|
['input', {
|
|
47
|
-
name: `${typeNamespace}-bigint`, type: 'number',
|
|
61
|
+
name: `${typeNamespace}-bigint`, type: 'number',
|
|
62
|
+
value: value ?? specificSchemaObject?.defaultValue ?? '',
|
|
63
|
+
min: bigintSchemaObject?.min
|
|
64
|
+
? bigintSchemaObject?.minInclusive
|
|
65
|
+
? bigintSchemaObject?.min
|
|
66
|
+
: String(BigInt(bigintSchemaObject?.min) + 1n)
|
|
67
|
+
: undefined,
|
|
68
|
+
max: bigintSchemaObject?.max
|
|
69
|
+
? bigintSchemaObject?.maxInclusive
|
|
70
|
+
? bigintSchemaObject?.max
|
|
71
|
+
: String(BigInt(bigintSchemaObject?.max) - 1n)
|
|
72
|
+
: undefined,
|
|
73
|
+
step: bigintSchemaObject?.multipleOf ?? '1'
|
|
48
74
|
}]
|
|
49
75
|
]];
|
|
50
76
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {jml} from '../vendor-imports.js';
|
|
1
|
+
import {jml, toStringTag} from '../vendor-imports.js';
|
|
2
2
|
import {$e} from '../utils/templateUtils.js';
|
|
3
3
|
import {visualize, getUserMedia, startScreenCapture} from '../utils/media.js';
|
|
4
4
|
import dialogs from '../utils/dialogs.js';
|
|
@@ -20,7 +20,7 @@ import dialogs from '../utils/dialogs.js';
|
|
|
20
20
|
* name?: string,
|
|
21
21
|
* type?: string
|
|
22
22
|
* }} value
|
|
23
|
-
* @returns {
|
|
23
|
+
* @returns {Blob}
|
|
24
24
|
*/
|
|
25
25
|
function newBlobForBinary (viewBinary, value) {
|
|
26
26
|
const oldBlob = /** @type {Blob|undefined} */ (
|
|
@@ -52,6 +52,7 @@ function newBlobForBinary (viewBinary, value) {
|
|
|
52
52
|
}
|
|
53
53
|
);
|
|
54
54
|
viewBinary.$value = blob;
|
|
55
|
+
return blob;
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
/**
|
|
@@ -97,9 +98,12 @@ function binaryButton (value, editable) {
|
|
|
97
98
|
const textarea = /** @type {HTMLTextAreaElement} */ (
|
|
98
99
|
$e(dialog, '.view-binary')
|
|
99
100
|
);
|
|
100
|
-
newBlobForBinary(viewBinary, {
|
|
101
|
+
const blob = newBlobForBinary(viewBinary, {
|
|
101
102
|
stringContents: textarea.value
|
|
102
103
|
});
|
|
104
|
+
// May need to update size:
|
|
105
|
+
/** @type {HTMLFieldSetElement & {$setValue: SetValue}} */
|
|
106
|
+
(viewBinary.parentElement).$setValue(blob);
|
|
103
107
|
dialog.close();
|
|
104
108
|
},
|
|
105
109
|
// @ts-expect-error TS bug
|
|
@@ -146,6 +150,9 @@ function binaryButton (value, editable) {
|
|
|
146
150
|
const blobType = {
|
|
147
151
|
option: ['Blob'],
|
|
148
152
|
stringRegex: /^Blob\((.*)\)$/u,
|
|
153
|
+
valueMatch (x) {
|
|
154
|
+
return toStringTag(x) === 'Blob';
|
|
155
|
+
},
|
|
149
156
|
toValue (s) {
|
|
150
157
|
const obj = JSON.parse(s);
|
|
151
158
|
return {value: new Blob([obj.stringContents], {
|
|
@@ -166,10 +173,13 @@ const blobType = {
|
|
|
166
173
|
this.getInput({root})
|
|
167
174
|
).$value;
|
|
168
175
|
},
|
|
169
|
-
viewUI ({value}) {
|
|
176
|
+
viewUI ({value, specificSchemaObject}) {
|
|
170
177
|
return ['div', {dataset: {type: 'blob'}}, [
|
|
171
|
-
['b', {
|
|
172
|
-
'
|
|
178
|
+
['b', {
|
|
179
|
+
class: 'emphasis',
|
|
180
|
+
title: specificSchemaObject?.description ? '(a Blob)' : undefined
|
|
181
|
+
}, [
|
|
182
|
+
specificSchemaObject?.description ?? 'Blob'
|
|
173
183
|
]],
|
|
174
184
|
['br'],
|
|
175
185
|
['br'],
|
|
@@ -185,7 +195,7 @@ const blobType = {
|
|
|
185
195
|
['br'],
|
|
186
196
|
value.type.startsWith('text/') || value.type === 'application/json'
|
|
187
197
|
? (() => {
|
|
188
|
-
const div =
|
|
198
|
+
const div = jml('div');
|
|
189
199
|
const reader = new FileReader();
|
|
190
200
|
reader.addEventListener('load', function () {
|
|
191
201
|
div.append(jml('div', [
|
|
@@ -217,7 +227,7 @@ const blobType = {
|
|
|
217
227
|
value.type.startsWith('video/')
|
|
218
228
|
? (() => {
|
|
219
229
|
const objURL = URL.createObjectURL(value);
|
|
220
|
-
const video =
|
|
230
|
+
const video = jml('video', {
|
|
221
231
|
src: objURL,
|
|
222
232
|
class: 'video',
|
|
223
233
|
$on: {
|
|
@@ -225,7 +235,7 @@ const blobType = {
|
|
|
225
235
|
URL.revokeObjectURL(objURL);
|
|
226
236
|
}
|
|
227
237
|
}
|
|
228
|
-
})
|
|
238
|
+
});
|
|
229
239
|
|
|
230
240
|
return ['div', [
|
|
231
241
|
video,
|
|
@@ -270,7 +280,7 @@ const blobType = {
|
|
|
270
280
|
value.type.startsWith('audio/')
|
|
271
281
|
? (() => {
|
|
272
282
|
const objURL = URL.createObjectURL(value);
|
|
273
|
-
const audio =
|
|
283
|
+
const audio = jml('audio', {
|
|
274
284
|
src: objURL,
|
|
275
285
|
class: 'audio',
|
|
276
286
|
$on: {
|
|
@@ -278,7 +288,7 @@ const blobType = {
|
|
|
278
288
|
URL.revokeObjectURL(objURL);
|
|
279
289
|
}
|
|
280
290
|
}
|
|
281
|
-
})
|
|
291
|
+
});
|
|
282
292
|
return ['div', [
|
|
283
293
|
audio,
|
|
284
294
|
['button', {
|
|
@@ -349,10 +359,13 @@ const blobType = {
|
|
|
349
359
|
: ''
|
|
350
360
|
]];
|
|
351
361
|
},
|
|
352
|
-
editUI ({typeNamespace, value = {}}) {
|
|
362
|
+
editUI ({typeNamespace, specificSchemaObject, value = {}}) {
|
|
353
363
|
// Todo: Could add way to preview blob in edit mode (whether
|
|
354
364
|
// recorded or uploaded)
|
|
355
|
-
return ['div', {
|
|
365
|
+
return ['div', {
|
|
366
|
+
dataset: {type: 'blob'},
|
|
367
|
+
title: specificSchemaObject?.description ?? 'Blob'
|
|
368
|
+
}, [
|
|
356
369
|
['fieldset', {
|
|
357
370
|
class: 'blobMetaData',
|
|
358
371
|
$custom: {
|
|
@@ -390,7 +403,7 @@ const blobType = {
|
|
|
390
403
|
['label', [
|
|
391
404
|
'Size (in bytes) ',
|
|
392
405
|
['input', {
|
|
393
|
-
type: 'number', disabled: true, class: 'size',
|
|
406
|
+
type: 'number', step: '1', disabled: true, class: 'size',
|
|
394
407
|
value: String(value.size)
|
|
395
408
|
}]
|
|
396
409
|
]],
|
|
@@ -481,194 +494,192 @@ const blobType = {
|
|
|
481
494
|
'Supply blob through recording'
|
|
482
495
|
]],
|
|
483
496
|
(() => {
|
|
484
|
-
const select =
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
);
|
|
497
|
+
const select = jml('select', {
|
|
498
|
+
class: 'device',
|
|
499
|
+
$on: {
|
|
500
|
+
async change () {
|
|
501
|
+
const videoContainer = /** @type {HTMLDivElement} */ (
|
|
502
|
+
this.nextElementSibling?.nextElementSibling
|
|
503
|
+
);
|
|
492
504
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
const oldVideo =
|
|
501
|
-
/**
|
|
502
|
-
* @type {HTMLVideoElement & {
|
|
503
|
-
* $stream: MediaStream
|
|
504
|
-
* }}
|
|
505
|
-
*/
|
|
506
|
-
($e(
|
|
507
|
-
videoContainer,
|
|
508
|
-
'video.previewMedia'
|
|
509
|
-
));
|
|
510
|
-
|
|
511
|
-
// Drop preexisting listeners
|
|
512
|
-
const previewMedia =
|
|
513
|
-
/**
|
|
514
|
-
* @type {HTMLVideoElement & {
|
|
515
|
-
* $stream: MediaStream,
|
|
516
|
-
* $screenShare: boolean
|
|
517
|
-
* }}
|
|
518
|
-
*/ (
|
|
519
|
-
jml('video', {
|
|
520
|
-
class: 'previewMedia'
|
|
521
|
-
})
|
|
522
|
-
);
|
|
523
|
-
|
|
524
|
-
if (oldVideo.$stream) {
|
|
525
|
-
const tracks = /** @type {MediaStream} */ (
|
|
526
|
-
oldVideo.$stream
|
|
527
|
-
).getTracks();
|
|
528
|
-
tracks.forEach((track) => {
|
|
529
|
-
track.stop();
|
|
530
|
-
});
|
|
531
|
-
oldVideo.srcObject = null;
|
|
532
|
-
}
|
|
505
|
+
const photo =
|
|
506
|
+
/**
|
|
507
|
+
* @type {HTMLCanvasElement}
|
|
508
|
+
*/
|
|
509
|
+
($e(videoContainer, 'img.photo'));
|
|
510
|
+
photo.hidden = true;
|
|
533
511
|
|
|
534
|
-
|
|
512
|
+
const oldVideo =
|
|
513
|
+
/**
|
|
514
|
+
* @type {HTMLVideoElement & {
|
|
515
|
+
* $stream: MediaStream
|
|
516
|
+
* }}
|
|
517
|
+
*/
|
|
518
|
+
($e(
|
|
519
|
+
videoContainer,
|
|
520
|
+
'video.previewMedia'
|
|
521
|
+
));
|
|
535
522
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
523
|
+
// Drop preexisting listeners
|
|
524
|
+
const previewMedia =
|
|
525
|
+
/**
|
|
526
|
+
* @type {HTMLVideoElement & {
|
|
527
|
+
* $stream: MediaStream,
|
|
528
|
+
* $screenShare: boolean
|
|
529
|
+
* }}
|
|
530
|
+
*/ (
|
|
531
|
+
jml('video', {
|
|
532
|
+
class: 'previewMedia'
|
|
533
|
+
})
|
|
540
534
|
);
|
|
541
535
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
)
|
|
536
|
+
if (oldVideo.$stream) {
|
|
537
|
+
const tracks = /** @type {MediaStream} */ (
|
|
538
|
+
oldVideo.$stream
|
|
539
|
+
).getTracks();
|
|
540
|
+
tracks.forEach((track) => {
|
|
541
|
+
track.stop();
|
|
542
|
+
});
|
|
543
|
+
oldVideo.srcObject = null;
|
|
544
|
+
}
|
|
547
545
|
|
|
548
|
-
|
|
549
|
-
/** @type {HTMLDivElement} */
|
|
550
|
-
(select.nextElementSibling?.
|
|
551
|
-
nextElementSibling),
|
|
552
|
-
'div.recordedMedia'
|
|
553
|
-
)).hidden = true;
|
|
546
|
+
oldVideo.replaceWith(previewMedia);
|
|
554
547
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
548
|
+
const takeSnapshot = /** @type {HTMLButtonElement} */ (
|
|
549
|
+
$e(/** @type {HTMLDivElement} */ (
|
|
550
|
+
select.nextElementSibling
|
|
551
|
+
), '.takeSnapshot')
|
|
552
|
+
);
|
|
558
553
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
*/
|
|
565
|
-
let constraints;
|
|
566
|
-
let screenShareConstraints;
|
|
567
|
-
|
|
568
|
-
previewMedia.$screenShare = false;
|
|
569
|
-
switch (select.value) {
|
|
570
|
-
case 'audio-and-video':
|
|
571
|
-
constraints = {video: true, audio: true};
|
|
572
|
-
previewMedia.hidden = false;
|
|
573
|
-
takeSnapshot.hidden = false;
|
|
574
|
-
recordMedia.textContent = 'Record video/audio';
|
|
575
|
-
break;
|
|
576
|
-
case 'video':
|
|
577
|
-
constraints = {video: true};
|
|
578
|
-
previewMedia.hidden = false;
|
|
579
|
-
takeSnapshot.hidden = false;
|
|
580
|
-
recordMedia.textContent = 'Record video';
|
|
581
|
-
break;
|
|
582
|
-
case 'audio':
|
|
583
|
-
constraints = {audio: true};
|
|
584
|
-
previewMedia.hidden = true;
|
|
585
|
-
takeSnapshot.hidden = true;
|
|
586
|
-
recordMedia.textContent = 'Record audio';
|
|
587
|
-
break;
|
|
588
|
-
case 'screenShare':
|
|
589
|
-
screenShareConstraints = {video: true};
|
|
590
|
-
// Fallthrough
|
|
591
|
-
case 'screenShareAndVideo':
|
|
592
|
-
if (!screenShareConstraints) {
|
|
593
|
-
screenShareConstraints = {video: true, audio: true};
|
|
594
|
-
}
|
|
595
|
-
previewMedia.$screenShare = true;
|
|
596
|
-
previewMedia.hidden = true;
|
|
597
|
-
takeSnapshot.hidden = true;
|
|
598
|
-
visualizer.hidden = true;
|
|
599
|
-
break;
|
|
600
|
-
default:
|
|
601
|
-
return;
|
|
602
|
-
}
|
|
554
|
+
const recordMedia = /** @type {HTMLButtonElement} */ (
|
|
555
|
+
$e(/** @type {HTMLDivElement} */ (
|
|
556
|
+
select.nextElementSibling
|
|
557
|
+
), '.recordMedia')
|
|
558
|
+
);
|
|
603
559
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
}
|
|
560
|
+
/** @type {HTMLDivElement} */ ($e(
|
|
561
|
+
/** @type {HTMLDivElement} */
|
|
562
|
+
(select.nextElementSibling?.
|
|
563
|
+
nextElementSibling),
|
|
564
|
+
'div.recordedMedia'
|
|
565
|
+
)).hidden = true;
|
|
611
566
|
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
// Save as stream for later reuse as stream
|
|
616
|
-
previewMedia.$stream = mediaStream;
|
|
617
|
-
|
|
618
|
-
if (constraints.video) {
|
|
619
|
-
const canvas =
|
|
620
|
-
/**
|
|
621
|
-
* @type {HTMLCanvasElement}
|
|
622
|
-
*/
|
|
623
|
-
($e(
|
|
624
|
-
videoContainer,
|
|
625
|
-
'canvas.recordedImage'
|
|
626
|
-
));
|
|
627
|
-
// https://developer.mozilla.org/en-US/docs/Web/API/Media_Capture_and_Streams_API/Taking_still_photos
|
|
628
|
-
previewMedia.addEventListener('canplay', () => {
|
|
629
|
-
canvas.setAttribute('width', String(
|
|
630
|
-
previewMedia.videoWidth
|
|
631
|
-
));
|
|
632
|
-
canvas.setAttribute(
|
|
633
|
-
'height', String(previewMedia.videoHeight)
|
|
634
|
-
);
|
|
635
|
-
});
|
|
636
|
-
}
|
|
567
|
+
const visualizer = /** @type {HTMLCanvasElement} */ (
|
|
568
|
+
$e(videoContainer, 'canvas.visualizer')
|
|
569
|
+
);
|
|
637
570
|
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
571
|
+
/**
|
|
572
|
+
* @type {{
|
|
573
|
+
* video?: true,
|
|
574
|
+
* audio?: true
|
|
575
|
+
* }|undefined}
|
|
576
|
+
*/
|
|
577
|
+
let constraints;
|
|
578
|
+
let screenShareConstraints;
|
|
579
|
+
|
|
580
|
+
previewMedia.$screenShare = false;
|
|
581
|
+
switch (select.value) {
|
|
582
|
+
case 'audio-and-video':
|
|
583
|
+
constraints = {video: true, audio: true};
|
|
584
|
+
previewMedia.hidden = false;
|
|
585
|
+
takeSnapshot.hidden = false;
|
|
586
|
+
recordMedia.textContent = 'Record video/audio';
|
|
587
|
+
break;
|
|
588
|
+
case 'video':
|
|
589
|
+
constraints = {video: true};
|
|
590
|
+
previewMedia.hidden = false;
|
|
591
|
+
takeSnapshot.hidden = false;
|
|
592
|
+
recordMedia.textContent = 'Record video';
|
|
593
|
+
break;
|
|
594
|
+
case 'audio':
|
|
595
|
+
constraints = {audio: true};
|
|
596
|
+
previewMedia.hidden = true;
|
|
597
|
+
takeSnapshot.hidden = true;
|
|
598
|
+
recordMedia.textContent = 'Record audio';
|
|
599
|
+
break;
|
|
600
|
+
case 'screenShare':
|
|
601
|
+
screenShareConstraints = {video: true};
|
|
602
|
+
// Fallthrough
|
|
603
|
+
case 'screenShareAndVideo':
|
|
604
|
+
if (!screenShareConstraints) {
|
|
605
|
+
screenShareConstraints = {video: true, audio: true};
|
|
606
|
+
}
|
|
607
|
+
previewMedia.$screenShare = true;
|
|
608
|
+
previewMedia.hidden = true;
|
|
609
|
+
takeSnapshot.hidden = true;
|
|
610
|
+
visualizer.hidden = true;
|
|
611
|
+
break;
|
|
612
|
+
default:
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
if (constraints) {
|
|
617
|
+
const mediaStream = await getUserMedia(constraints);
|
|
618
|
+
/* istanbul ignore if */
|
|
619
|
+
if (!mediaStream) {
|
|
620
|
+
await dialogs.alert('Error getting user media');
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
videoContainer.hidden = false;
|
|
625
|
+
previewMedia.srcObject = mediaStream;
|
|
626
|
+
|
|
627
|
+
// Save as stream for later reuse as stream
|
|
628
|
+
previewMedia.$stream = mediaStream;
|
|
629
|
+
|
|
630
|
+
if (constraints.video) {
|
|
631
|
+
const canvas =
|
|
632
|
+
/**
|
|
633
|
+
* @type {HTMLCanvasElement}
|
|
634
|
+
*/
|
|
635
|
+
($e(
|
|
636
|
+
videoContainer,
|
|
637
|
+
'canvas.recordedImage'
|
|
638
|
+
));
|
|
639
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/Media_Capture_and_Streams_API/Taking_still_photos
|
|
640
|
+
previewMedia.addEventListener('canplay', () => {
|
|
641
|
+
canvas.setAttribute('width', String(
|
|
642
|
+
previewMedia.videoWidth
|
|
643
|
+
));
|
|
644
|
+
canvas.setAttribute(
|
|
645
|
+
'height', String(previewMedia.videoHeight)
|
|
646
|
+
);
|
|
649
647
|
});
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
);
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
previewMedia.addEventListener('loadedmetadata', () => {
|
|
651
|
+
previewMedia.play();
|
|
652
|
+
if (constraints?.audio) {
|
|
653
|
+
visualizer.hidden = false;
|
|
654
|
+
visualize(
|
|
655
|
+
mediaStream,
|
|
656
|
+
visualizer
|
|
657
|
+
);
|
|
658
|
+
} else {
|
|
659
|
+
visualizer.hidden = true;
|
|
658
660
|
}
|
|
661
|
+
});
|
|
662
|
+
} else if (screenShareConstraints) {
|
|
663
|
+
const mediaStream = await startScreenCapture(
|
|
664
|
+
screenShareConstraints
|
|
665
|
+
);
|
|
666
|
+
/* istanbul ignore if */
|
|
667
|
+
if (!mediaStream) {
|
|
668
|
+
await dialogs.alert('Error getting user media');
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
659
671
|
|
|
660
|
-
|
|
661
|
-
|
|
672
|
+
videoContainer.hidden = false;
|
|
673
|
+
previewMedia.srcObject = mediaStream;
|
|
662
674
|
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
}
|
|
675
|
+
// Save as stream for later reuse as stream
|
|
676
|
+
previewMedia.$stream = mediaStream;
|
|
666
677
|
}
|
|
667
678
|
}
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
]
|
|
671
|
-
);
|
|
679
|
+
}
|
|
680
|
+
}, [
|
|
681
|
+
['option', {value: ''}, ['Please choose a device']]
|
|
682
|
+
]);
|
|
672
683
|
|
|
673
684
|
(async () => {
|
|
674
685
|
const devices = await navigator.mediaDevices.enumerateDevices();
|
|
@@ -770,7 +781,7 @@ const blobType = {
|
|
|
770
781
|
try {
|
|
771
782
|
mediaRecorder.start();
|
|
772
783
|
/* istanbul ignore next */
|
|
773
|
-
} catch
|
|
784
|
+
} catch {
|
|
774
785
|
/* istanbul ignore next */
|
|
775
786
|
dialogs.alert('Error starting media recorder');
|
|
776
787
|
/* istanbul ignore next */
|
|
@@ -909,9 +920,9 @@ const blobType = {
|
|
|
909
920
|
dialogs.alert('Error converting canvas to Blob');
|
|
910
921
|
return;
|
|
911
922
|
}
|
|
912
|
-
const newPhoto =
|
|
923
|
+
const newPhoto = jml('img', {
|
|
913
924
|
class: 'photo'
|
|
914
|
-
})
|
|
925
|
+
});
|
|
915
926
|
const url = URL.createObjectURL(blob);
|
|
916
927
|
|
|
917
928
|
newPhoto.addEventListener('load', () => {
|
|
@@ -951,9 +962,9 @@ const blobType = {
|
|
|
951
962
|
{class: 'recordedMedia'},
|
|
952
963
|
/** @type {import('jamilih').JamilihChildren} */ ([
|
|
953
964
|
...(() => {
|
|
954
|
-
const recordedMedia =
|
|
965
|
+
const recordedMedia = jml(
|
|
955
966
|
'video', {class: 'recordedMedia'}
|
|
956
|
-
)
|
|
967
|
+
);
|
|
957
968
|
return [
|
|
958
969
|
recordedMedia,
|
|
959
970
|
['br'],
|