@es-joy/jsoe 0.2.0 → 0.4.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/.eslintignore +3 -0
- package/.eslintrc.cjs +2 -0
- package/.ncurc.cjs +9 -0
- package/CHANGES.md +9 -0
- package/README.md +2 -2
- package/demo/index.html +8 -0
- package/demo/index.js +1 -1
- package/dist/formatAndTypeChoices.d.ts +56 -0
- package/dist/formatAndTypeChoices.d.ts.map +1 -0
- package/dist/formats/indexedDBKey.d.ts +4 -0
- package/dist/formats/indexedDBKey.d.ts.map +1 -0
- package/dist/formats/json.d.ts +4 -0
- package/dist/formats/json.d.ts.map +1 -0
- package/dist/formats/schemaAndArbitrary.d.ts +6 -0
- package/dist/formats/schemaAndArbitrary.d.ts.map +1 -0
- package/dist/formats/schemaOnly.d.ts +6 -0
- package/dist/formats/schemaOnly.d.ts.map +1 -0
- package/dist/formats/structuredCloning.d.ts +20 -0
- package/dist/formats/structuredCloning.d.ts.map +1 -0
- package/dist/formats.d.ts +26 -0
- package/dist/formats.d.ts.map +1 -0
- package/dist/fundamentalTypes/BooleanObjectType.d.ts +8 -0
- package/dist/fundamentalTypes/BooleanObjectType.d.ts.map +1 -0
- package/dist/fundamentalTypes/NumberObjectType.d.ts +6 -0
- package/dist/fundamentalTypes/NumberObjectType.d.ts.map +1 -0
- package/dist/fundamentalTypes/StringObjectType.d.ts +6 -0
- package/dist/fundamentalTypes/StringObjectType.d.ts.map +1 -0
- package/dist/fundamentalTypes/arrayReferenceType.d.ts +8 -0
- package/dist/fundamentalTypes/arrayReferenceType.d.ts.map +1 -0
- package/dist/fundamentalTypes/arrayType.d.ts +60 -0
- package/dist/fundamentalTypes/arrayType.d.ts.map +1 -0
- package/dist/fundamentalTypes/bigintType.d.ts +6 -0
- package/dist/fundamentalTypes/bigintType.d.ts.map +1 -0
- package/dist/fundamentalTypes/dateType.d.ts +26 -0
- package/dist/fundamentalTypes/dateType.d.ts.map +1 -0
- package/dist/fundamentalTypes/nullType.d.ts +6 -0
- package/dist/fundamentalTypes/nullType.d.ts.map +1 -0
- package/dist/fundamentalTypes/numberType.d.ts +6 -0
- package/dist/fundamentalTypes/numberType.d.ts.map +1 -0
- package/dist/fundamentalTypes/objectReferenceType.d.ts +8 -0
- package/dist/fundamentalTypes/objectReferenceType.d.ts.map +1 -0
- package/dist/fundamentalTypes/objectType.d.ts +6 -0
- package/dist/fundamentalTypes/objectType.d.ts.map +1 -0
- package/dist/fundamentalTypes/regexpType.d.ts +8 -0
- package/dist/fundamentalTypes/regexpType.d.ts.map +1 -0
- package/dist/fundamentalTypes/sparseUndefinedType.d.ts +6 -0
- package/dist/fundamentalTypes/sparseUndefinedType.d.ts.map +1 -0
- package/dist/fundamentalTypes/stringType.d.ts +6 -0
- package/dist/fundamentalTypes/stringType.d.ts.map +1 -0
- package/dist/fundamentalTypes/undefinedType.d.ts +6 -0
- package/dist/fundamentalTypes/undefinedType.d.ts.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/src/deepEqual.d.ts +3 -0
- package/dist/src/deepEqual.d.ts.map +1 -0
- package/dist/src/formatAndTypeChoices.d.ts +47 -0
- package/dist/src/formatAndTypeChoices.d.ts.map +1 -0
- package/dist/src/formats/indexedDBKey.d.ts +9 -0
- package/dist/src/formats/indexedDBKey.d.ts.map +1 -0
- package/dist/src/formats/json.d.ts +9 -0
- package/dist/src/formats/json.d.ts.map +1 -0
- package/dist/src/formats/schemaAndArbitrary.d.ts +6 -0
- package/dist/src/formats/schemaAndArbitrary.d.ts.map +1 -0
- package/dist/src/formats/schemaOnly.d.ts +6 -0
- package/dist/src/formats/schemaOnly.d.ts.map +1 -0
- package/dist/src/formats/structuredCloning.d.ts +15 -0
- package/dist/src/formats/structuredCloning.d.ts.map +1 -0
- package/dist/src/formats.d.ts +18 -0
- package/dist/src/formats.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/BooleanObjectType.d.ts +6 -0
- package/dist/src/fundamentalTypes/BooleanObjectType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/NumberObjectType.d.ts +6 -0
- package/dist/src/fundamentalTypes/NumberObjectType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/StringObjectType.d.ts +6 -0
- package/dist/src/fundamentalTypes/StringObjectType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/arrayReferenceType.d.ts +6 -0
- package/dist/src/fundamentalTypes/arrayReferenceType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/arrayType.d.ts +6 -0
- package/dist/src/fundamentalTypes/arrayType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/bigintType.d.ts +6 -0
- package/dist/src/fundamentalTypes/bigintType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/dateType.d.ts +6 -0
- package/dist/src/fundamentalTypes/dateType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/nullType.d.ts +6 -0
- package/dist/src/fundamentalTypes/nullType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/numberType.d.ts +6 -0
- package/dist/src/fundamentalTypes/numberType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/objectReferenceType.d.ts +6 -0
- package/dist/src/fundamentalTypes/objectReferenceType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/objectType.d.ts +6 -0
- package/dist/src/fundamentalTypes/objectType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/regexpType.d.ts +6 -0
- package/dist/src/fundamentalTypes/regexpType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/sparseUndefinedType.d.ts +6 -0
- package/dist/src/fundamentalTypes/sparseUndefinedType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/stringType.d.ts +6 -0
- package/dist/src/fundamentalTypes/stringType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/undefinedType.d.ts +6 -0
- package/dist/src/fundamentalTypes/undefinedType.d.ts.map +1 -0
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/subTypes/blobHTMLType.d.ts +26 -0
- package/dist/src/subTypes/blobHTMLType.d.ts.map +1 -0
- package/dist/src/subTypes/falseType.d.ts +6 -0
- package/dist/src/subTypes/falseType.d.ts.map +1 -0
- package/dist/src/subTypes/trueType.d.ts +6 -0
- package/dist/src/subTypes/trueType.d.ts.map +1 -0
- package/dist/src/superTypes/SpecialNumberSuperType.d.ts +11 -0
- package/dist/src/superTypes/SpecialNumberSuperType.d.ts.map +1 -0
- package/dist/src/superTypes/SpecialRealNumberSuperType.d.ts +6 -0
- package/dist/src/superTypes/SpecialRealNumberSuperType.d.ts.map +1 -0
- package/dist/src/typeChoices.d.ts +30 -0
- package/dist/src/typeChoices.d.ts.map +1 -0
- package/dist/src/types.d.ts +333 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/utils/dialogs.d.ts +29 -0
- package/dist/src/utils/dialogs.d.ts.map +1 -0
- package/dist/src/utils/jsonPointer.d.ts +42 -0
- package/dist/src/utils/jsonPointer.d.ts.map +1 -0
- package/dist/src/utils/templateUtils.d.ts +59 -0
- package/dist/src/utils/templateUtils.d.ts.map +1 -0
- package/dist/src/utils/types.d.ts +2 -0
- package/dist/src/utils/types.d.ts.map +1 -0
- package/dist/subTypes/blobHTMLType.d.ts +14 -0
- package/dist/subTypes/blobHTMLType.d.ts.map +1 -0
- package/dist/subTypes/falseType.d.ts +8 -0
- package/dist/subTypes/falseType.d.ts.map +1 -0
- package/dist/subTypes/trueType.d.ts +8 -0
- package/dist/subTypes/trueType.d.ts.map +1 -0
- package/dist/superTypes/SpecialNumberSuperType.d.ts +14 -0
- package/dist/superTypes/SpecialNumberSuperType.d.ts.map +1 -0
- package/dist/superTypes/SpecialRealNumberSuperType.d.ts +6 -0
- package/dist/superTypes/SpecialRealNumberSuperType.d.ts.map +1 -0
- package/dist/typeChoices.d.ts +103 -0
- package/dist/typeChoices.d.ts.map +1 -0
- package/dist/types.d.ts +523 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils/dialogs.d.ts +109 -0
- package/dist/utils/dialogs.d.ts.map +1 -0
- package/dist/utils/jsonPointer.d.ts +46 -0
- package/dist/utils/jsonPointer.d.ts.map +1 -0
- package/dist/utils/templateUtils.d.ts +59 -0
- package/dist/utils/templateUtils.d.ts.map +1 -0
- package/dist/utils/types.d.ts +2 -0
- package/dist/utils/types.d.ts.map +1 -0
- package/dist/vendor/jamilih/dist/jml-es.d.ts +436 -0
- package/dist/vendor/jamilih/dist/jml-es.d.ts.map +1 -0
- package/dist/vendor/typeson-registry/dist/index.d.ts +400 -0
- package/dist/vendor/typeson-registry/dist/index.d.ts.map +1 -0
- package/dist/vendor-imports.d.ts +3 -0
- package/dist/vendor-imports.d.ts.map +1 -0
- package/package.json +19 -14
- package/postorder-traversal.js +58 -0
- package/src/formatAndTypeChoices.js +95 -50
- package/src/formats/indexedDBKey.js +49 -56
- package/src/formats/json.js +47 -56
- package/src/formats/schemaOnly.js +12 -2
- package/src/formats/structuredCloning.js +162 -105
- package/src/formats.js +38 -10
- package/src/fundamentalTypes/BooleanObjectType.js +6 -4
- package/src/fundamentalTypes/NumberObjectType.js +5 -3
- package/src/fundamentalTypes/StringObjectType.js +1 -1
- package/src/fundamentalTypes/arrayReferenceType.js +29 -14
- package/src/fundamentalTypes/arrayType.js +789 -278
- package/src/fundamentalTypes/bigintType.js +2 -2
- package/src/fundamentalTypes/dateType.js +42 -14
- package/src/fundamentalTypes/nullType.js +1 -1
- package/src/fundamentalTypes/numberType.js +2 -2
- package/src/fundamentalTypes/objectReferenceType.js +7 -5
- package/src/fundamentalTypes/regexpType.js +45 -24
- package/src/fundamentalTypes/sparseUndefinedType.js +7 -1
- package/src/fundamentalTypes/stringType.js +1 -1
- package/src/fundamentalTypes/undefinedType.js +2 -2
- package/src/jsoe.css +1 -1
- package/src/subTypes/blobHTMLType.js +42 -22
- package/src/subTypes/falseType.js +2 -2
- package/src/subTypes/trueType.js +2 -2
- package/src/superTypes/SpecialNumberSuperType.js +30 -16
- package/src/superTypes/SpecialRealNumberSuperType.js +62 -0
- package/src/typeChoices.js +137 -55
- package/src/types.js +312 -148
- package/src/utils/dialogs.js +98 -29
- package/src/utils/jsonPointer.js +4 -0
- package/src/utils/templateUtils.js +27 -12
- package/src/vendor-imports.js +8 -0
- package/tsconfig.json +18 -0
- package/typings/sceditor.d.ts +20 -0
- package/vendor/jamilih/dist/jml-es.js +1019 -389
- package/vendor/jamilih/dist/jml.d.ts +436 -0
- package/vendor/jamilih/package.json +136 -0
- package/vendor/typeson-registry/dist/index.js +382 -84
- package/src/superTypes/InfinitiesSuperType.js +0 -49
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {jml, nbsp} from '
|
|
1
|
+
import {jml, nbsp} from '../vendor-imports.js';
|
|
2
2
|
|
|
3
3
|
import Types, {getPropertyValueFromLegend} from '../types.js';
|
|
4
4
|
import {$e, U, DOM} from '../utils/templateUtils.js';
|
|
@@ -8,35 +8,86 @@ import {
|
|
|
8
8
|
} from '../utils/jsonPointer.js';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* @
|
|
11
|
+
* @typedef {number} Integer
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* @callback ParseInt
|
|
15
|
+
* @this {HTMLInputElement}
|
|
16
|
+
* @returns {false|Integer}
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* @typedef {() => HTMLInputElement[]} InputsExceedingLength
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* @callback GetPropertyInputs
|
|
23
|
+
* @returns {HTMLInputElement[]}
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @callback RedrawMoveArrows
|
|
28
|
+
* @returns {void}
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* @typedef {() => HTMLDivElement & {
|
|
32
|
+
* $inputsExceedingLength: InputsExceedingLength,
|
|
33
|
+
* $getPropertyInputs: GetPropertyInputs,
|
|
34
|
+
* $redrawMoveArrows: RedrawMoveArrows
|
|
35
|
+
* }} GetArrayItems
|
|
36
|
+
*/
|
|
37
|
+
/**
|
|
38
|
+
* @typedef {() => Promise<void>} Validate
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @callback Resort
|
|
43
|
+
* @param {{alwaysFocus?: true}} cfg
|
|
44
|
+
* @returns {void}
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @typedef {() => HTMLInputElement|undefined} GetPropertyInput
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @type {import('../types.js').TypeObject & {sparse?: boolean|undefined}}
|
|
12
53
|
*/
|
|
13
54
|
const arrayType = {
|
|
14
55
|
option: ['Array'],
|
|
15
56
|
array: true,
|
|
57
|
+
// sparse: undefined, // Don't add as will be copied
|
|
16
58
|
regexEndings: [',', ']'],
|
|
17
59
|
stringRegexBegin: /^\[/u,
|
|
18
60
|
stringRegexEnd: /^\]/u,
|
|
19
|
-
toValue (s, {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
61
|
+
toValue (s, info) {
|
|
62
|
+
const {
|
|
63
|
+
/* istanbul ignore next -- Just a guard */
|
|
64
|
+
endMatchTypeObjs = [],
|
|
65
|
+
remnant: innerContents,
|
|
66
|
+
rootHolder
|
|
67
|
+
} = /** @type {import('../types.js').RootInfo} */ (info);
|
|
68
|
+
// eslint-disable-next-line prefer-destructuring -- TS
|
|
69
|
+
const format = /** @type {import('../types.js').RootInfo} */ (info).format;
|
|
70
|
+
|
|
26
71
|
const {sparse} = this;
|
|
27
72
|
const state = sparse
|
|
28
73
|
? 'arrayNonindexKeys'
|
|
29
74
|
// ? 'sparseArrays'
|
|
30
75
|
: (this.array ? 'array' : 'object');
|
|
76
|
+
/** @type {{[key: (string|number)]: any}} */
|
|
31
77
|
const retObj = this.array ? [] : {};
|
|
32
78
|
let stringVal = innerContents !== undefined
|
|
33
79
|
? innerContents
|
|
34
80
|
/* istanbul ignore next -- Unreachable? */
|
|
35
81
|
: s;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @param {boolean} beginOnly
|
|
85
|
+
* @returns {boolean}
|
|
86
|
+
*/
|
|
36
87
|
const checkEnd = (beginOnly) => {
|
|
37
88
|
if (beginOnly && endMatchTypeObjs.length) {
|
|
38
89
|
const endMatch = stringVal.match(
|
|
39
|
-
endMatchTypeObjs.slice(-1)[0].stringRegexEnd
|
|
90
|
+
/** @type {RegExp} */ (endMatchTypeObjs.slice(-1)[0].stringRegexEnd)
|
|
40
91
|
);
|
|
41
92
|
if (endMatch) {
|
|
42
93
|
endMatchTypeObjs.pop(); // Safe now to extract
|
|
@@ -90,6 +141,11 @@ const arrayType = {
|
|
|
90
141
|
}
|
|
91
142
|
return {value: retObj, remnant: stringVal};
|
|
92
143
|
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* @param {boolean} [notFirstRun]
|
|
147
|
+
* @returns {void}
|
|
148
|
+
*/
|
|
93
149
|
const parse = (notFirstRun) => {
|
|
94
150
|
if (!stringVal) {
|
|
95
151
|
return;
|
|
@@ -122,7 +178,10 @@ const arrayType = {
|
|
|
122
178
|
}
|
|
123
179
|
// console.log('vvv', stringVal, beginOnly, v);
|
|
124
180
|
if (assign) {
|
|
125
|
-
|
|
181
|
+
// eslint-disable-next-line max-len -- Long
|
|
182
|
+
/** @type {{[key: string]: import('../formats.js').StructuredCloneValue}} */ (
|
|
183
|
+
retObj
|
|
184
|
+
)[pr] = v;
|
|
126
185
|
}
|
|
127
186
|
if (checkEnd(beginOnly)) {
|
|
128
187
|
return;
|
|
@@ -134,19 +193,31 @@ const arrayType = {
|
|
|
134
193
|
},
|
|
135
194
|
getValue ({root, stateObj = {}, currentPath = ''}) {
|
|
136
195
|
const top = currentPath === '';
|
|
137
|
-
const arrayItems = $e(root, '.arrayItems');
|
|
196
|
+
const arrayItems = /** @type {Element} */ ($e(root, '.arrayItems'));
|
|
138
197
|
const fieldsets = arrayItems.children;
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* @type {({[key: string]: any})|any[]}
|
|
201
|
+
*/
|
|
139
202
|
const ret = root.dataset.type === 'object'
|
|
140
203
|
? {}
|
|
141
204
|
: !this.sparse
|
|
142
205
|
? []
|
|
143
|
-
: Array.from({length: Number.parseInt(
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
206
|
+
: Array.from({length: Number.parseInt(
|
|
207
|
+
/** @type {HTMLInputElement} */ (DOM.filterChildElements(
|
|
208
|
+
root,
|
|
209
|
+
['div', 'div', 'label', 'input']
|
|
210
|
+
)[0]).value
|
|
211
|
+
)});
|
|
147
212
|
|
|
148
213
|
// Todo: Should this be renamed per return arguments to
|
|
149
214
|
// `getRefOrVal` or is it ok?
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* @param {HTMLDivElement} root
|
|
218
|
+
* @param {string} currentPathPart
|
|
219
|
+
* @returns {[boolean, boolean?]}
|
|
220
|
+
*/
|
|
150
221
|
const getValOrRef = (root, currentPathPart) => {
|
|
151
222
|
const value = Types.getValueForRoot(
|
|
152
223
|
root, stateObj, currentPath + '/' + currentPathPart
|
|
@@ -160,21 +231,25 @@ const arrayType = {
|
|
|
160
231
|
};
|
|
161
232
|
[...fieldsets].forEach((fieldset) => {
|
|
162
233
|
const legend = fieldset.firstElementChild;
|
|
163
|
-
const propVal = getPropertyValueFromLegend(
|
|
164
|
-
|
|
234
|
+
const propVal = getPropertyValueFromLegend(
|
|
235
|
+
/** @type {HTMLLegendElement} */ (legend)
|
|
236
|
+
);
|
|
237
|
+
const root = /** @type {HTMLDivElement} */ (
|
|
238
|
+
$e(fieldset, 'div[data-type]')
|
|
239
|
+
);
|
|
165
240
|
/* istanbul ignore if -- Should err first? */
|
|
166
241
|
if (!root) {
|
|
167
242
|
return;
|
|
168
243
|
}
|
|
169
244
|
|
|
170
|
-
const objectProperty = $e(legend, 'input');
|
|
245
|
+
const objectProperty = $e(/** @type {Element} */ (legend), 'input');
|
|
171
246
|
const [isVal, value] = getValOrRef(
|
|
172
247
|
root,
|
|
173
248
|
propVal
|
|
174
249
|
);
|
|
175
250
|
if (isVal) {
|
|
176
251
|
if (objectProperty) {
|
|
177
|
-
ret[propVal] = value;
|
|
252
|
+
/** @type {{[key: string]: any}} */ (ret)[propVal] = value;
|
|
178
253
|
} else {
|
|
179
254
|
ret.push(value);
|
|
180
255
|
}
|
|
@@ -190,13 +265,15 @@ const arrayType = {
|
|
|
190
265
|
obj: ret
|
|
191
266
|
});
|
|
192
267
|
|
|
193
|
-
|
|
194
|
-
const referenceFinalPathPart =
|
|
195
|
-
const referenceParentObj =
|
|
268
|
+
const referencePathJsonPtr = getJSONPointerParts(referencePath);
|
|
269
|
+
const referenceFinalPathPart = referencePathJsonPtr.pop();
|
|
270
|
+
const referenceParentObj = referencePathJsonPtr.reduce(
|
|
196
271
|
(obj, pathPart) => reduceJSONPointerParts(obj, pathPart),
|
|
197
272
|
ret
|
|
198
273
|
);
|
|
199
|
-
|
|
274
|
+
/** @type {{[key: string]: any}} */ (referenceParentObj)[
|
|
275
|
+
/** @type {string} */ (referenceFinalPathPart)
|
|
276
|
+
] = referentObj;
|
|
200
277
|
}
|
|
201
278
|
);
|
|
202
279
|
}
|
|
@@ -207,6 +284,15 @@ const arrayType = {
|
|
|
207
284
|
viewUI ({typeNamespace, type, value, topRoot, resultType, format}) {
|
|
208
285
|
// const {sparse} = this;
|
|
209
286
|
let itemIndex = -1;
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* @param {{
|
|
290
|
+
* itemIndex: number,
|
|
291
|
+
* typeNamespace?: string,
|
|
292
|
+
* propName: string
|
|
293
|
+
* }} cfg
|
|
294
|
+
* @returns {import('jamilih').JamilihArray}
|
|
295
|
+
*/
|
|
210
296
|
const buildLegend = ({
|
|
211
297
|
/* className, type, arrayItems, */
|
|
212
298
|
itemIndex, typeNamespace, propName
|
|
@@ -228,74 +314,105 @@ const arrayType = {
|
|
|
228
314
|
]]
|
|
229
315
|
]];
|
|
230
316
|
};
|
|
231
|
-
const div =
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
$
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
317
|
+
const div = /** @type {HTMLDivElement} */ (
|
|
318
|
+
jml('div', /** @type {import('jamilih').JamilihAttributes} */ ({
|
|
319
|
+
class: 'arrayHolder',
|
|
320
|
+
dataset: {type},
|
|
321
|
+
$custom: {
|
|
322
|
+
/**
|
|
323
|
+
* @param {{
|
|
324
|
+
* propName: name,
|
|
325
|
+
* type: import('../types.js').AvailableType,
|
|
326
|
+
* value: import('../formats.js').StructuredCloneValue,
|
|
327
|
+
* bringIntoFocus: boolean,
|
|
328
|
+
* schemaContent: object,
|
|
329
|
+
* schemaState:
|
|
330
|
+
* import('../types.js').GetPossibleSchemasForPathAndType
|
|
331
|
+
* }} cfg
|
|
332
|
+
* @returns {Element}
|
|
333
|
+
*/
|
|
334
|
+
$addAndSetArrayElement ({
|
|
335
|
+
propName, type, value, bringIntoFocus,
|
|
336
|
+
schemaContent, schemaState
|
|
337
|
+
}) {
|
|
338
|
+
const fieldset = this.$addArrayElement({propName});
|
|
339
|
+
const root = Types.getUIForModeAndType({
|
|
340
|
+
resultType,
|
|
341
|
+
readonly: true,
|
|
342
|
+
typeNamespace, type, topRoot,
|
|
343
|
+
bringIntoFocus,
|
|
344
|
+
format, schemaContent, schemaState,
|
|
345
|
+
value,
|
|
346
|
+
hasValue: true // type === 'sparseArrays' && value
|
|
347
|
+
});
|
|
348
|
+
jml(root, fieldset);
|
|
349
|
+
return root;
|
|
350
|
+
},
|
|
351
|
+
/**
|
|
352
|
+
* @param {{propName: string}} cfg
|
|
353
|
+
* @returns {HTMLFieldSetElement}
|
|
354
|
+
*/
|
|
355
|
+
$addArrayElement ({propName}) {
|
|
356
|
+
itemIndex++;
|
|
357
|
+
const arrayItems = this.$getArrayItems();
|
|
358
|
+
// const className = `${type}Item`;
|
|
359
|
+
const fieldset = /** @type {HTMLFieldSetElement} */ (
|
|
360
|
+
jml('fieldset', [
|
|
361
|
+
buildLegend({
|
|
362
|
+
// className,
|
|
363
|
+
// type,
|
|
364
|
+
// arrayItems,
|
|
365
|
+
itemIndex,
|
|
366
|
+
typeNamespace,
|
|
367
|
+
propName
|
|
368
|
+
})
|
|
369
|
+
], arrayItems)
|
|
370
|
+
);
|
|
371
|
+
return fieldset;
|
|
372
|
+
},
|
|
373
|
+
$getArrayItems () {
|
|
374
|
+
return this.lastElementChild.lastElementChild;
|
|
375
|
+
}
|
|
266
376
|
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
377
|
+
}), [
|
|
378
|
+
DOM.initialCaps(/** @type {import('../types.js').AvailableType} */ (
|
|
379
|
+
type
|
|
380
|
+
)).replace(/s$/u, ''), nbsp.repeat(2),
|
|
381
|
+
// Why is this necessary
|
|
382
|
+
/** @type {import('jamilih').JamilihArray} */
|
|
383
|
+
(['button', {$on: {click (/** @type {Event} */ e) {
|
|
384
|
+
e.preventDefault();
|
|
385
|
+
const {target} = e;
|
|
386
|
+
const arrayContents = /** @type {HTMLDivElement} */ ($e(
|
|
387
|
+
/** @type {Element} */
|
|
388
|
+
(/** @type {Element} */ (target).closest('.arrayHolder')),
|
|
389
|
+
'.arrayContents'
|
|
390
|
+
));
|
|
391
|
+
arrayContents.hidden = !arrayContents.hidden;
|
|
392
|
+
/** @type {Element} */ (
|
|
393
|
+
target
|
|
394
|
+
).textContent = arrayContents.hidden ? '+' : '-';
|
|
395
|
+
}}}, ['-']]),
|
|
396
|
+
['div', {class: 'arrayContents'}, [
|
|
397
|
+
this.array
|
|
398
|
+
? ['div', [
|
|
399
|
+
'Array length: ',
|
|
400
|
+
['span', [
|
|
401
|
+
(value && value.length) || 0
|
|
402
|
+
]]
|
|
286
403
|
]]
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
]
|
|
293
|
-
|
|
404
|
+
: '',
|
|
405
|
+
['div', {
|
|
406
|
+
class: 'arrayItems'
|
|
407
|
+
}]
|
|
408
|
+
]]
|
|
409
|
+
])
|
|
410
|
+
);
|
|
294
411
|
return [div];
|
|
295
412
|
},
|
|
296
413
|
getInput ({root}) {
|
|
297
414
|
// One element we are guaranteed to have for adding validation
|
|
298
|
-
return $e(root, 'button');
|
|
415
|
+
return /** @type {HTMLButtonElement} */ ($e(root, 'button'));
|
|
299
416
|
},
|
|
300
417
|
// Unlike other items, we don't use the `value`, as it wil always be
|
|
301
418
|
// an array (or object if called by that method) and we handle the
|
|
@@ -308,16 +425,34 @@ const arrayType = {
|
|
|
308
425
|
const itemAdjust = type === 'object' ? 1 : 0;
|
|
309
426
|
let itemIndex = itemAdjust - 1;
|
|
310
427
|
const editableProperties = type !== 'array';
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* @param {HTMLInputElement} input
|
|
431
|
+
* @param {true|undefined} alwaysFocus
|
|
432
|
+
* @returns {void}
|
|
433
|
+
*/
|
|
311
434
|
const bringFocus = (input, alwaysFocus) => {
|
|
312
435
|
if (bringIntoFocus || alwaysFocus) {
|
|
313
436
|
input.scrollIntoView();
|
|
314
437
|
input.focus();
|
|
315
438
|
}
|
|
316
439
|
};
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* @callback SwapGroup
|
|
443
|
+
* @param {Element} holder
|
|
444
|
+
* @param {"up"|"down"} direction
|
|
445
|
+
* @returns {void}
|
|
446
|
+
*/
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* @type {SwapGroup}
|
|
450
|
+
* @this {HTMLDivElement}
|
|
451
|
+
*/
|
|
317
452
|
const $swapGroup = function (holder, direction) {
|
|
318
|
-
const group = holder.parentElement;
|
|
453
|
+
const group = /** @type {HTMLElement} */ (holder.parentElement);
|
|
319
454
|
const swapGroup = group[
|
|
320
|
-
(direction === 'up' ? '
|
|
455
|
+
(direction === 'up' ? 'previousElementSibling' : 'nextElementSibling')
|
|
321
456
|
];
|
|
322
457
|
/* istanbul ignore if -- Just a guard */
|
|
323
458
|
if (!swapGroup || swapGroup.nodeName.toLowerCase() !== 'fieldset') {
|
|
@@ -336,8 +471,20 @@ const arrayType = {
|
|
|
336
471
|
swapCountElem.textContent = base;
|
|
337
472
|
baseCountElem.textContent = swap;
|
|
338
473
|
} else {
|
|
339
|
-
|
|
340
|
-
const
|
|
474
|
+
// eslint-disable-next-line max-len -- Long
|
|
475
|
+
const swapCountElem = /** @type {HTMLInputElement & {$parseInt: ParseInt}} */
|
|
476
|
+
(/**
|
|
477
|
+
* @type {HTMLFieldSetElement & {$getPropertyInput: GetPropertyInput}}
|
|
478
|
+
*/ (
|
|
479
|
+
group
|
|
480
|
+
).$getPropertyInput());
|
|
481
|
+
// eslint-disable-next-line max-len -- Long
|
|
482
|
+
const baseCountElem = /** @type {HTMLInputElement & {$parseInt: ParseInt}} */
|
|
483
|
+
(/**
|
|
484
|
+
* @type {HTMLFieldSetElement & {$getPropertyInput: GetPropertyInput}}
|
|
485
|
+
*/ (
|
|
486
|
+
swapGroup
|
|
487
|
+
).$getPropertyInput());
|
|
341
488
|
if (typeof swapCountElem.$parseInt() === 'number' ||
|
|
342
489
|
typeof baseCountElem.$parseInt() === 'number'
|
|
343
490
|
) {
|
|
@@ -358,9 +505,20 @@ const arrayType = {
|
|
|
358
505
|
} else {
|
|
359
506
|
group.before(swapGroup);
|
|
360
507
|
}
|
|
361
|
-
Types.validateAllReferences({
|
|
362
|
-
|
|
508
|
+
Types.validateAllReferences({
|
|
509
|
+
// eslint-disable-next-line object-shorthand -- TS
|
|
510
|
+
topRoot: /** @type {HTMLDivElement} */ (topRoot)
|
|
511
|
+
}); // Needed
|
|
512
|
+
|
|
513
|
+
/** @type {HTMLDivElement & {$redrawMoveArrows: RedrawMoveArrows}} */ (
|
|
514
|
+
this
|
|
515
|
+
).$redrawMoveArrows();
|
|
363
516
|
};
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* @type {RedrawMoveArrows}
|
|
520
|
+
* @this {HTMLDivElement & {$swapGroup: SwapGroup}}
|
|
521
|
+
*/
|
|
364
522
|
const $redrawMoveArrows = function () {
|
|
365
523
|
DOM.filterChildElements(this, [
|
|
366
524
|
'fieldset', `.${type}Item-arrowHolder-${typeNamespace}`
|
|
@@ -387,6 +545,19 @@ const arrayType = {
|
|
|
387
545
|
}
|
|
388
546
|
});
|
|
389
547
|
};
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* @typedef {() => void} ValidateLegend
|
|
551
|
+
*/
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* @type {ValidateLegend}
|
|
555
|
+
* @this {HTMLInputElement & {
|
|
556
|
+
* $arrayItems: HTMLDivElement & {
|
|
557
|
+
* $getPropertyInputs: GetPropertyInputs
|
|
558
|
+
* }
|
|
559
|
+
* }}
|
|
560
|
+
*/
|
|
390
561
|
const $validateLegend = function () {
|
|
391
562
|
const propertyNameInputs = this.$arrayItems.$getPropertyInputs();
|
|
392
563
|
const invalidStr = propertyNameInputs.some((input) => {
|
|
@@ -425,10 +596,42 @@ const arrayType = {
|
|
|
425
596
|
return invalidStr; // Don't give a chance to become valid
|
|
426
597
|
});
|
|
427
598
|
};
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* @typedef {HTMLDivElement & {
|
|
602
|
+
* $inputsExceedingLength: InputsExceedingLength,
|
|
603
|
+
* $getPropertyInputs: GetPropertyInputs,
|
|
604
|
+
* $redrawMoveArrows: RedrawMoveArrows
|
|
605
|
+
* }} ArrayItems
|
|
606
|
+
*/
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* @param {{
|
|
610
|
+
* className: string,
|
|
611
|
+
* splice: "append"|number|undefined,
|
|
612
|
+
* itemIndex: number,
|
|
613
|
+
* typeNamespace: string|undefined,
|
|
614
|
+
* arrayItems: ArrayItems,
|
|
615
|
+
* propName: string|undefined
|
|
616
|
+
* }} cfg
|
|
617
|
+
* @returns {import('jamilih').JamilihArray}
|
|
618
|
+
*/
|
|
428
619
|
const buildLegend = ({
|
|
429
620
|
className, splice, itemIndex, /* type, */ typeNamespace,
|
|
430
621
|
arrayItems, propName
|
|
431
622
|
}) => {
|
|
623
|
+
/**
|
|
624
|
+
* @callback ValidateLength
|
|
625
|
+
* @param {boolean} [avoidDialog]
|
|
626
|
+
* @returns {Promise<void>}
|
|
627
|
+
*/
|
|
628
|
+
|
|
629
|
+
/**
|
|
630
|
+
* @type {ValidateLength}
|
|
631
|
+
* @this {HTMLInputElement & {
|
|
632
|
+
* $validateLength: ValidateLength
|
|
633
|
+
* }}
|
|
634
|
+
*/
|
|
432
635
|
const $validateLength = async function (avoidDialog) {
|
|
433
636
|
if (!sparse) {
|
|
434
637
|
return undefined;
|
|
@@ -443,15 +646,20 @@ const arrayType = {
|
|
|
443
646
|
'array item beyond the length. Click "Ok" to allow to ' +
|
|
444
647
|
'permit and extend the array length or "Cancel" otherwise.'
|
|
445
648
|
});
|
|
446
|
-
const arrLengthInput =
|
|
649
|
+
const arrLengthInput = /** @type {HTMLInputElement} */ (
|
|
650
|
+
$e(
|
|
651
|
+
/** @type {Element} */ (arrayItems.previousElementSibling),
|
|
652
|
+
'input'
|
|
653
|
+
)
|
|
654
|
+
);
|
|
447
655
|
const highest = inputsExceedingLength.map(
|
|
448
656
|
(i) => Number.parseInt(i.value)
|
|
449
657
|
).sort().slice(-1)[0];
|
|
450
|
-
arrLengthInput.value = highest + 1;
|
|
658
|
+
arrLengthInput.value = String(highest + 1);
|
|
451
659
|
return this.$validateLength(true);
|
|
452
660
|
};
|
|
453
|
-
|
|
454
|
-
|
|
661
|
+
if (editableProperties) {
|
|
662
|
+
return /** @type {import('jamilih').JamilihArray} */ (['legend', [
|
|
455
663
|
sparse
|
|
456
664
|
? 'Item'
|
|
457
665
|
: {'#': [
|
|
@@ -476,6 +684,13 @@ const arrayType = {
|
|
|
476
684
|
pattern: sparse ? '\\d' : '',
|
|
477
685
|
*/
|
|
478
686
|
$custom: {
|
|
687
|
+
/**
|
|
688
|
+
* @type {Validate}
|
|
689
|
+
* @this {HTMLInputElement & {
|
|
690
|
+
* $validateLength: ValidateLength,
|
|
691
|
+
* $validateLegend: ValidateLegend
|
|
692
|
+
* }}
|
|
693
|
+
*/
|
|
479
694
|
async $validate () {
|
|
480
695
|
try {
|
|
481
696
|
try {
|
|
@@ -487,9 +702,17 @@ const arrayType = {
|
|
|
487
702
|
/* await */ this.$validateLegend();
|
|
488
703
|
// Todo (low): We could make this more efficient by waiting
|
|
489
704
|
// until all added (when pre-populating)
|
|
490
|
-
Types.validateAllReferences({
|
|
705
|
+
Types.validateAllReferences({
|
|
706
|
+
// eslint-disable-next-line object-shorthand -- TS
|
|
707
|
+
topRoot: /** @type {HTMLDivElement} */ (topRoot)
|
|
708
|
+
}); // Needed
|
|
491
709
|
} catch (err) {}
|
|
492
710
|
},
|
|
711
|
+
|
|
712
|
+
/**
|
|
713
|
+
* @type {ParseInt}
|
|
714
|
+
* @this {HTMLInputElement}
|
|
715
|
+
*/
|
|
493
716
|
$parseInt () {
|
|
494
717
|
if (!(/^\d+$/u).test(this.value)) {
|
|
495
718
|
return false;
|
|
@@ -499,20 +722,49 @@ const arrayType = {
|
|
|
499
722
|
$validateLegend,
|
|
500
723
|
$arrayItems: arrayItems,
|
|
501
724
|
$validateLength,
|
|
725
|
+
/**
|
|
726
|
+
* @type {Resort}
|
|
727
|
+
* @this {HTMLInputElement}
|
|
728
|
+
*/
|
|
502
729
|
$resort ({alwaysFocus}) {
|
|
503
|
-
const inputs =
|
|
730
|
+
const inputs = /**
|
|
731
|
+
* @type {(HTMLInputElement & {
|
|
732
|
+
* $parseInt: ParseInt
|
|
733
|
+
* })[]}
|
|
734
|
+
*/
|
|
735
|
+
(/**
|
|
736
|
+
* @type {HTMLInputElement & {
|
|
737
|
+
* $arrayItems: HTMLDivElement & {
|
|
738
|
+
* $getPropertyInputs: GetPropertyInputs
|
|
739
|
+
* }
|
|
740
|
+
* }}
|
|
741
|
+
*/ (
|
|
742
|
+
this
|
|
743
|
+
).$arrayItems.$getPropertyInputs());
|
|
504
744
|
if (inputs.length === 1) {
|
|
505
745
|
return;
|
|
506
746
|
}
|
|
507
|
-
|
|
747
|
+
/**
|
|
748
|
+
* @param {Element} el
|
|
749
|
+
* @returns {Element}
|
|
750
|
+
*/
|
|
751
|
+
const getFieldset = (el) => /** @type {HTMLFieldSetElement} */ (
|
|
752
|
+
el.closest('fieldset')
|
|
753
|
+
);
|
|
508
754
|
const thisFieldset = getFieldset(this);
|
|
509
|
-
|
|
755
|
+
// eslint-disable-next-line max-len -- Long
|
|
756
|
+
const intVal = /** @type {HTMLInputElement & {$parseInt: ParseInt}} */ (
|
|
757
|
+
this
|
|
758
|
+
).$parseInt();
|
|
510
759
|
if (intVal === false) {
|
|
511
760
|
inputs.reverse().some((input) => {
|
|
512
761
|
if (input === this) { // No need to search further
|
|
513
762
|
return true;
|
|
514
763
|
}
|
|
515
|
-
const intValOlder =
|
|
764
|
+
const intValOlder =
|
|
765
|
+
/** @type {HTMLInputElement & {$parseInt: ParseInt}} */ (
|
|
766
|
+
input
|
|
767
|
+
).$parseInt();
|
|
516
768
|
// Not sorting non-integers
|
|
517
769
|
if (typeof intValOlder !== 'number') {
|
|
518
770
|
return false;
|
|
@@ -524,8 +776,17 @@ const arrayType = {
|
|
|
524
776
|
});
|
|
525
777
|
return;
|
|
526
778
|
}
|
|
779
|
+
|
|
780
|
+
/**
|
|
781
|
+
* @param {boolean} [latest]
|
|
782
|
+
* @returns {boolean}
|
|
783
|
+
*/
|
|
527
784
|
const getNearest = (latest) => {
|
|
785
|
+
/**
|
|
786
|
+
* @type {HTMLInputElement|undefined}
|
|
787
|
+
*/
|
|
528
788
|
let nearest;
|
|
789
|
+
|
|
529
790
|
inputs.some((input) => {
|
|
530
791
|
if (input === this) {
|
|
531
792
|
return false;
|
|
@@ -539,6 +800,12 @@ const arrayType = {
|
|
|
539
800
|
}
|
|
540
801
|
return false;
|
|
541
802
|
}
|
|
803
|
+
|
|
804
|
+
/**
|
|
805
|
+
* @param {Integer} a
|
|
806
|
+
* @param {Integer} b
|
|
807
|
+
* @returns {boolean}
|
|
808
|
+
*/
|
|
542
809
|
const cmp = (a, b) => {
|
|
543
810
|
return latest ? a > b : a < b;
|
|
544
811
|
};
|
|
@@ -558,6 +825,10 @@ const arrayType = {
|
|
|
558
825
|
const method = latest ? 'after' : 'before';
|
|
559
826
|
// Ensure move *after* splice that will occur after this
|
|
560
827
|
setTimeout(() => {
|
|
828
|
+
/* c8 ignore next 3 */
|
|
829
|
+
if (!nearest) {
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
561
832
|
getFieldset(nearest)[method](thisFieldset);
|
|
562
833
|
bringFocus(this, alwaysFocus);
|
|
563
834
|
arrayItems.$redrawMoveArrows();
|
|
@@ -570,6 +841,13 @@ const arrayType = {
|
|
|
570
841
|
}
|
|
571
842
|
},
|
|
572
843
|
$on: {
|
|
844
|
+
/**
|
|
845
|
+
* @param {Event} e
|
|
846
|
+
* @this {HTMLInputElement & {
|
|
847
|
+
* $validate: Validate,
|
|
848
|
+
* $resort: Resort
|
|
849
|
+
* }}
|
|
850
|
+
*/
|
|
573
851
|
change (e) {
|
|
574
852
|
this.$validate();
|
|
575
853
|
// We don't want form `onchange` to run
|
|
@@ -580,20 +858,31 @@ const arrayType = {
|
|
|
580
858
|
},
|
|
581
859
|
class: `propertyName-${typeNamespace}`
|
|
582
860
|
}]
|
|
861
|
+
]]);
|
|
862
|
+
}
|
|
863
|
+
return /** @type {import('jamilih').JamilihArray} */ (['legend', [
|
|
864
|
+
'Item ',
|
|
865
|
+
['span', {
|
|
866
|
+
dataset: {prop: true, array: true},
|
|
867
|
+
className
|
|
868
|
+
}, [
|
|
869
|
+
propName !== undefined ? propName : String(itemIndex)
|
|
583
870
|
]]
|
|
584
|
-
|
|
585
|
-
'Item ',
|
|
586
|
-
['span', {
|
|
587
|
-
dataset: {prop: true, array: true},
|
|
588
|
-
className
|
|
589
|
-
}, [
|
|
590
|
-
propName !== undefined ? propName : String(itemIndex)
|
|
591
|
-
]]
|
|
592
|
-
]];
|
|
871
|
+
]]);
|
|
593
872
|
};
|
|
873
|
+
|
|
874
|
+
/**
|
|
875
|
+
* @param {HTMLDivElement & {
|
|
876
|
+
* $getPropertyInputs: GetPropertyInputs
|
|
877
|
+
* }} arrayItems
|
|
878
|
+
* @returns {void}
|
|
879
|
+
*/
|
|
594
880
|
const decrementItemIndex = (arrayItems) => {
|
|
595
881
|
if (sparse) {
|
|
596
|
-
|
|
882
|
+
// eslint-disable-next-line max-len -- Long
|
|
883
|
+
itemIndex = /** @type {(HTMLInputElement & {$parseInt: ParseInt})[]} */ (
|
|
884
|
+
arrayItems.$getPropertyInputs()
|
|
885
|
+
).reduce(
|
|
597
886
|
(highest, input) => {
|
|
598
887
|
const intVal = input.$parseInt();
|
|
599
888
|
return intVal !== false && intVal > highest ? intVal : highest;
|
|
@@ -604,6 +893,24 @@ const arrayType = {
|
|
|
604
893
|
itemIndex--;
|
|
605
894
|
}
|
|
606
895
|
};
|
|
896
|
+
|
|
897
|
+
/**
|
|
898
|
+
* @callback AddArrayElement
|
|
899
|
+
* @param {{
|
|
900
|
+
* propName?: string,
|
|
901
|
+
* splice?: "append"|number,
|
|
902
|
+
* alwaysFocus?: true
|
|
903
|
+
* }} cfg
|
|
904
|
+
* @returns {void}
|
|
905
|
+
*/
|
|
906
|
+
|
|
907
|
+
/**
|
|
908
|
+
* @type {AddArrayElement}
|
|
909
|
+
* @this {HTMLButtonElement & {
|
|
910
|
+
* $getArrayItems: GetArrayItems,
|
|
911
|
+
* $addArrayElement: AddArrayElement
|
|
912
|
+
* }}
|
|
913
|
+
*/
|
|
607
914
|
const $addArrayElement = function ({propName, splice, alwaysFocus}) {
|
|
608
915
|
// console.log('propName', propName);
|
|
609
916
|
const arrayItems = this.$getArrayItems();
|
|
@@ -616,7 +923,12 @@ const arrayType = {
|
|
|
616
923
|
} else if (typeof splice === 'number') {
|
|
617
924
|
itemIndex = splice + 1;
|
|
618
925
|
} else if (typeof splice !== 'string') {
|
|
619
|
-
|
|
926
|
+
// eslint-disable-next-line max-len -- Long
|
|
927
|
+
itemIndex = /** @type {(HTMLInputElement & {$parseInt: ParseInt})[]} */ (
|
|
928
|
+
// eslint-disable-next-line max-len -- Long
|
|
929
|
+
/** @type {HTMLDivElement & {$getPropertyInputs: GetPropertyInputs}} */
|
|
930
|
+
(arrayItems).$getPropertyInputs()
|
|
931
|
+
).reduce(
|
|
620
932
|
(highest, input) => {
|
|
621
933
|
const intVal = input.$parseInt();
|
|
622
934
|
return intVal !== false && intVal > highest ? intVal : highest;
|
|
@@ -629,47 +941,74 @@ const arrayType = {
|
|
|
629
941
|
}
|
|
630
942
|
const thisButton = this; // eslint-disable-line consistent-this
|
|
631
943
|
const className = `${type}Item`;
|
|
632
|
-
const fieldset = jml('fieldset', {
|
|
944
|
+
const fieldset = /** @type {HTMLFieldSetElement} */ (jml('fieldset', {
|
|
633
945
|
$custom: {
|
|
946
|
+
/** @type {GetPropertyInput} */
|
|
634
947
|
$getPropertyInput () {
|
|
635
|
-
return DOM.filterChildElements(
|
|
636
|
-
this,
|
|
948
|
+
return /** @type {HTMLInputElement} */ (DOM.filterChildElements(
|
|
949
|
+
/** @type {HTMLFieldSetElement} */ (this),
|
|
637
950
|
['legend', `input.propertyName-${typeNamespace}`]
|
|
638
|
-
).pop();
|
|
951
|
+
).pop());
|
|
639
952
|
}
|
|
640
953
|
}
|
|
641
954
|
}, [
|
|
642
955
|
buildLegend({
|
|
643
|
-
className,
|
|
644
|
-
|
|
956
|
+
className,
|
|
957
|
+
splice,
|
|
958
|
+
itemIndex,
|
|
959
|
+
// type,
|
|
960
|
+
typeNamespace,
|
|
961
|
+
arrayItems,
|
|
962
|
+
propName
|
|
645
963
|
})
|
|
646
|
-
], arrayItems);
|
|
964
|
+
], arrayItems));
|
|
647
965
|
// We must ensure fieldset is built before passing it
|
|
648
966
|
jml({'#': [
|
|
649
|
-
...(
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
967
|
+
...(/** @type {import('../typeChoices.js').BuildTypeChoices} */ (
|
|
968
|
+
buildTypeChoices
|
|
969
|
+
)({
|
|
970
|
+
// resultType,
|
|
971
|
+
// eslint-disable-next-line object-shorthand -- TS
|
|
972
|
+
topRoot: /** @type {HTMLDivElement} */ (topRoot),
|
|
973
|
+
// eslint-disable-next-line object-shorthand, max-len -- TS
|
|
974
|
+
format: /** @type {import('../formats.js').AvailableFormat} */ (format),
|
|
653
975
|
state: type,
|
|
654
|
-
itemIndex,
|
|
976
|
+
// itemIndex,
|
|
655
977
|
typeNamespace
|
|
656
978
|
}).domArray),
|
|
657
979
|
nbsp.repeat(2),
|
|
658
|
-
['button', {$on: {click (e) {
|
|
980
|
+
['button', {$on: {click (/** @type {Event} */ e) {
|
|
659
981
|
e.preventDefault();
|
|
660
982
|
// e.stopPropagation();
|
|
661
983
|
let splice;
|
|
662
984
|
if (sparse) {
|
|
663
|
-
const prevInputVal =
|
|
985
|
+
const prevInputVal =
|
|
986
|
+
/**
|
|
987
|
+
* @type {HTMLInputElement & {
|
|
988
|
+
* $parseInt: ParseInt
|
|
989
|
+
* }}
|
|
990
|
+
*/ (
|
|
991
|
+
/**
|
|
992
|
+
* @type {HTMLFieldSetElement & {
|
|
993
|
+
* $getPropertyInput: GetPropertyInput
|
|
994
|
+
* }}
|
|
995
|
+
*/ (
|
|
996
|
+
fieldset
|
|
997
|
+
).$getPropertyInput()).$parseInt();
|
|
664
998
|
splice = prevInputVal === false ? 'append' : prevInputVal;
|
|
665
999
|
}
|
|
666
1000
|
thisButton.$addArrayElement({
|
|
667
1001
|
splice, alwaysFocus: true
|
|
668
1002
|
});
|
|
669
|
-
const newArrayFieldset =
|
|
1003
|
+
const newArrayFieldset =
|
|
1004
|
+
/** @type {Element & {$getPropertyInput: GetPropertyInput}} */ (
|
|
1005
|
+
arrayItems.lastElementChild
|
|
1006
|
+
);
|
|
670
1007
|
fieldset.after(newArrayFieldset);
|
|
671
1008
|
if (sparse) {
|
|
672
|
-
const newPrevInput =
|
|
1009
|
+
const newPrevInput = /** @type {HTMLInputElement} */ (
|
|
1010
|
+
newArrayFieldset.$getPropertyInput()
|
|
1011
|
+
);
|
|
673
1012
|
bringFocus(newPrevInput, true);
|
|
674
1013
|
} else {
|
|
675
1014
|
DOM.filterChildElements(
|
|
@@ -677,31 +1016,56 @@ const arrayType = {
|
|
|
677
1016
|
'fieldset', 'legend', '.' + className
|
|
678
1017
|
]
|
|
679
1018
|
).forEach((span, i) => {
|
|
680
|
-
span.textContent =
|
|
1019
|
+
span.textContent = String(i + itemAdjust);
|
|
681
1020
|
});
|
|
682
1021
|
}
|
|
683
1022
|
// Maybe not needed as addition (without renumbering)
|
|
684
1023
|
// wouldn't yet add type
|
|
685
|
-
Types.validateAllReferences({
|
|
1024
|
+
Types.validateAllReferences({
|
|
1025
|
+
// eslint-disable-next-line object-shorthand -- TS
|
|
1026
|
+
topRoot: /** @type {HTMLDivElement} */ (topRoot)
|
|
1027
|
+
});
|
|
686
1028
|
arrayItems.$redrawMoveArrows();
|
|
687
1029
|
}}}, ['+']],
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
1030
|
+
/**
|
|
1031
|
+
* @type {import('jamilih').JamilihArray}
|
|
1032
|
+
*/
|
|
1033
|
+
([
|
|
1034
|
+
'button',
|
|
1035
|
+
// @ts-ignore Can't seem to force optional Event
|
|
1036
|
+
{
|
|
1037
|
+
$on: {
|
|
1038
|
+
click (/** @type {Event} */ e) {
|
|
1039
|
+
e.preventDefault();
|
|
1040
|
+
// e.stopPropagation();
|
|
1041
|
+
fieldset.remove();
|
|
1042
|
+
decrementItemIndex(arrayItems);
|
|
1043
|
+
if (!sparse) {
|
|
1044
|
+
DOM.filterChildElements(arrayItems, [
|
|
1045
|
+
'fieldset', 'legend', '.' + className
|
|
1046
|
+
]).forEach((span, i) => {
|
|
1047
|
+
span.textContent = String(i + itemAdjust);
|
|
1048
|
+
});
|
|
1049
|
+
}
|
|
1050
|
+
// Maybe not needed as removal would remove circular
|
|
1051
|
+
Types.validateAllReferences({
|
|
1052
|
+
// eslint-disable-next-line object-shorthand -- TS
|
|
1053
|
+
topRoot: /** @type {HTMLDivElement} */ (topRoot)
|
|
1054
|
+
});
|
|
1055
|
+
|
|
1056
|
+
/**
|
|
1057
|
+
* @type {HTMLDivElement & {
|
|
1058
|
+
* $redrawMoveArrows: RedrawMoveArrows
|
|
1059
|
+
* }}
|
|
1060
|
+
*/
|
|
1061
|
+
(arrayItems).$redrawMoveArrows();
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
}, ['x']
|
|
1065
|
+
]),
|
|
1066
|
+
['span', {
|
|
1067
|
+
class: `${type}Item-arrowHolder-${typeNamespace}`
|
|
1068
|
+
}, []]
|
|
705
1069
|
]}, fieldset);
|
|
706
1070
|
// Need to validate if adding more than one property (in
|
|
707
1071
|
// case two have empty string)
|
|
@@ -709,7 +1073,14 @@ const arrayType = {
|
|
|
709
1073
|
const pns = arrayItems.$getPropertyInputs();
|
|
710
1074
|
/* istanbul ignore else -- Just a guard */
|
|
711
1075
|
if (pns.length) {
|
|
712
|
-
const input =
|
|
1076
|
+
const input =
|
|
1077
|
+
/**
|
|
1078
|
+
* @type {HTMLInputElement & {
|
|
1079
|
+
* $validate: Validate,
|
|
1080
|
+
* $resort: Resort
|
|
1081
|
+
* }}
|
|
1082
|
+
*/
|
|
1083
|
+
(pns.pop());
|
|
713
1084
|
input.$validate();
|
|
714
1085
|
input.$resort({alwaysFocus});
|
|
715
1086
|
bringFocus(input, alwaysFocus);
|
|
@@ -718,9 +1089,28 @@ const arrayType = {
|
|
|
718
1089
|
arrayItems.$redrawMoveArrows();
|
|
719
1090
|
};
|
|
720
1091
|
|
|
1092
|
+
/**
|
|
1093
|
+
* @callback GetArrayLength
|
|
1094
|
+
* @returns {number}
|
|
1095
|
+
*/
|
|
1096
|
+
|
|
1097
|
+
/**
|
|
1098
|
+
* @type {GetArrayLength}
|
|
1099
|
+
* @this {HTMLDivElement}
|
|
1100
|
+
*/
|
|
721
1101
|
const $getArrayLength = function () {
|
|
722
|
-
return
|
|
1102
|
+
return Number(/** @type {HTMLInputElement} */ (
|
|
1103
|
+
$e(/** @type {Element} */ (this.previousElementSibling), 'input')
|
|
1104
|
+
).value);
|
|
723
1105
|
};
|
|
1106
|
+
|
|
1107
|
+
/**
|
|
1108
|
+
* @type {InputsExceedingLength}
|
|
1109
|
+
* @this {HTMLDivElement & {
|
|
1110
|
+
* $getArrayLength: GetArrayLength,
|
|
1111
|
+
* $getPropertyInputs: GetPropertyInputs
|
|
1112
|
+
* }}
|
|
1113
|
+
*/
|
|
724
1114
|
const $inputsExceedingLength = function () {
|
|
725
1115
|
const highestExpectedIndex = this.$getArrayLength() - 1;
|
|
726
1116
|
return this.$getPropertyInputs().filter(
|
|
@@ -738,147 +1128,176 @@ const arrayType = {
|
|
|
738
1128
|
return exceedsLength;
|
|
739
1129
|
});
|
|
740
1130
|
};
|
|
741
|
-
const
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
$
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
},
|
|
763
|
-
$addArrayElement ({propName, splice, alwaysFocus}) {
|
|
764
|
-
const addArrayElement = this.$getAddArrayElement();
|
|
765
|
-
addArrayElement.$addArrayElement({propName, splice, alwaysFocus});
|
|
766
|
-
},
|
|
767
|
-
$getArrayItems () {
|
|
768
|
-
const addArrayElement = this.$getAddArrayElement();
|
|
769
|
-
return addArrayElement.previousElementSibling;
|
|
1131
|
+
const addArrayElement = /** @type {import('jamilih').JamilihArray} */ (
|
|
1132
|
+
['button', {
|
|
1133
|
+
class: 'addArrayElement',
|
|
1134
|
+
// is: 'add-array-element',
|
|
1135
|
+
$custom: {
|
|
1136
|
+
$addArrayElement,
|
|
1137
|
+
/**
|
|
1138
|
+
* @type {GetArrayItems}
|
|
1139
|
+
* @this {HTMLDivElement}
|
|
1140
|
+
*/
|
|
1141
|
+
$getArrayItems () {
|
|
1142
|
+
return (/**
|
|
1143
|
+
* @type {HTMLDivElement & {
|
|
1144
|
+
* $inputsExceedingLength: InputsExceedingLength,
|
|
1145
|
+
* $getPropertyInputs: GetPropertyInputs,
|
|
1146
|
+
* $redrawMoveArrows: RedrawMoveArrows
|
|
1147
|
+
* }}
|
|
1148
|
+
*/
|
|
1149
|
+
(this.previousElementSibling)
|
|
1150
|
+
);
|
|
1151
|
+
}
|
|
770
1152
|
},
|
|
771
|
-
$
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
['
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
}
|
|
1153
|
+
$on: {click () {
|
|
1154
|
+
/**
|
|
1155
|
+
* @type {HTMLButtonElement & {
|
|
1156
|
+
* $addArrayElement: AddArrayElement,
|
|
1157
|
+
* $getArrayItems: GetArrayItems
|
|
1158
|
+
* }}
|
|
1159
|
+
*/
|
|
1160
|
+
(this).$addArrayElement({alwaysFocus: true});
|
|
1161
|
+
// Maybe not needed as addition (without renumbering)
|
|
1162
|
+
// wouldn't yet add type
|
|
1163
|
+
Types.validateAllReferences({
|
|
1164
|
+
// eslint-disable-next-line object-shorthand -- TS
|
|
1165
|
+
topRoot: /** @type {HTMLDivElement} */ (topRoot)
|
|
1166
|
+
});
|
|
1167
|
+
}}
|
|
1168
|
+
}, ['+ Item']]
|
|
1169
|
+
);
|
|
1170
|
+
|
|
1171
|
+
const arrayContentsFirstChild = sparse
|
|
1172
|
+
? ['div', [
|
|
1173
|
+
['label', [
|
|
1174
|
+
'Array length: ',
|
|
1175
|
+
['input', {
|
|
1176
|
+
type: 'number',
|
|
1177
|
+
value: (value && value.length) || 0,
|
|
1178
|
+
step: 1,
|
|
1179
|
+
size: 4,
|
|
1180
|
+
pattern: '\\d',
|
|
1181
|
+
$on: {
|
|
1182
|
+
/**
|
|
1183
|
+
* @this {HTMLInputElement & {
|
|
1184
|
+
* $oldvalue: string
|
|
1185
|
+
* }}
|
|
1186
|
+
* @returns {Promise<void>}
|
|
1187
|
+
*/
|
|
1188
|
+
async change () {
|
|
1189
|
+
const arrayItems = $e(
|
|
1190
|
+
/** @type {Element} */ (
|
|
1191
|
+
this.closest('.arrayContents')
|
|
1192
|
+
),
|
|
1193
|
+
'.arrayItems'
|
|
1194
|
+
);
|
|
1195
|
+
const propInputsBeyondLength =
|
|
1196
|
+
/**
|
|
1197
|
+
* @type {HTMLElement & {
|
|
1198
|
+
* $inputsExceedingLength: InputsExceedingLength
|
|
1199
|
+
* }}
|
|
1200
|
+
*/
|
|
1201
|
+
(arrayItems).$inputsExceedingLength();
|
|
1202
|
+
try {
|
|
1203
|
+
if (propInputsBeyondLength.length) {
|
|
1204
|
+
await dialogs.confirm({
|
|
1205
|
+
message: 'Your new length will truncate the ' +
|
|
1206
|
+
'array causing items to be removed. Continue?'
|
|
1207
|
+
});
|
|
1208
|
+
propInputsBeyondLength.forEach((input) => {
|
|
1209
|
+
const fieldset = /** @type {HTMLFieldSetElement} */ (
|
|
1210
|
+
input.closest('fieldset')
|
|
1211
|
+
);
|
|
1212
|
+
fieldset.remove();
|
|
1213
|
+
});
|
|
1214
|
+
// Maybe not needed as removal would remove circular
|
|
1215
|
+
Types.validateAllReferences({
|
|
1216
|
+
// eslint-disable-next-line object-shorthand -- TS
|
|
1217
|
+
topRoot: /** @type {HTMLDivElement} */ (topRoot)
|
|
1218
|
+
});
|
|
832
1219
|
}
|
|
1220
|
+
this.$oldvalue = this.value;
|
|
1221
|
+
} catch (err) {
|
|
1222
|
+
this.value = this.$oldvalue; // Revert
|
|
833
1223
|
}
|
|
834
|
-
}
|
|
835
|
-
]]
|
|
836
|
-
]]
|
|
837
|
-
: '',
|
|
838
|
-
['div', {
|
|
839
|
-
class: 'arrayItems',
|
|
840
|
-
$custom: {
|
|
841
|
-
$swapGroup, $redrawMoveArrows, $getArrayLength,
|
|
842
|
-
$inputsExceedingLength,
|
|
843
|
-
$getPropertyInputs () {
|
|
844
|
-
return DOM.filterChildElements(
|
|
845
|
-
this,
|
|
846
|
-
['fieldset', 'legend', `input.propertyName-${typeNamespace}`]
|
|
847
|
-
);
|
|
1224
|
+
}
|
|
848
1225
|
}
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
1226
|
+
}]
|
|
1227
|
+
]]
|
|
1228
|
+
]]
|
|
1229
|
+
: '';
|
|
1230
|
+
|
|
1231
|
+
const arrayItems = ['div', {
|
|
1232
|
+
class: 'arrayItems',
|
|
1233
|
+
$custom: {
|
|
1234
|
+
$swapGroup, $redrawMoveArrows, $getArrayLength,
|
|
1235
|
+
$inputsExceedingLength,
|
|
1236
|
+
|
|
1237
|
+
/**
|
|
1238
|
+
* @type {GetPropertyInputs}
|
|
1239
|
+
* @this {HTMLDivElement}
|
|
1240
|
+
*/
|
|
1241
|
+
$getPropertyInputs () {
|
|
1242
|
+
return /** @type {HTMLInputElement[]} */ (DOM.filterChildElements(
|
|
1243
|
+
this,
|
|
1244
|
+
['fieldset', 'legend', `input.propertyName-${typeNamespace}`]
|
|
1245
|
+
));
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
}];
|
|
1249
|
+
|
|
1250
|
+
const minusButton = ['button', {$on: {click (/** @type {Event} */ e) {
|
|
1251
|
+
e.preventDefault();
|
|
1252
|
+
const {target} = e;
|
|
1253
|
+
const arrayContents = /** @type {HTMLDivElement} */ (
|
|
1254
|
+
$e(div, '.arrayContents')
|
|
1255
|
+
);
|
|
1256
|
+
arrayContents.hidden = !arrayContents.hidden;
|
|
1257
|
+
/** @type {Element} */ (
|
|
1258
|
+
target
|
|
1259
|
+
).textContent = arrayContents.hidden ? '+' : '-';
|
|
1260
|
+
}}}, ['-']];
|
|
1261
|
+
|
|
1262
|
+
const arrayContents = /** @type {import('jamilih').JamilihArray} */ (
|
|
1263
|
+
['div', {class: 'arrayContents'}, [
|
|
1264
|
+
arrayContentsFirstChild,
|
|
1265
|
+
arrayItems,
|
|
1266
|
+
addArrayElement,
|
|
864
1267
|
['button', {$on: {click () {
|
|
865
|
-
const arrayContents =
|
|
866
|
-
|
|
1268
|
+
const arrayContents = /** @type {Element} */ (
|
|
1269
|
+
this.closest('.arrayContents')
|
|
1270
|
+
);
|
|
1271
|
+
const arrayItems =
|
|
1272
|
+
// eslint-disable-next-line max-len -- Long
|
|
1273
|
+
/** @type {HTMLDivElement & {$getPropertyInputs: GetPropertyInputs;}} */ (
|
|
1274
|
+
$e(arrayContents, '.arrayItems')
|
|
1275
|
+
);
|
|
867
1276
|
const lastElement = arrayItems.lastElementChild;
|
|
868
1277
|
if (lastElement) {
|
|
869
1278
|
lastElement.remove();
|
|
870
1279
|
decrementItemIndex(arrayItems);
|
|
871
|
-
|
|
1280
|
+
// eslint-disable-next-line max-len -- Long
|
|
1281
|
+
/** @type {HTMLDivElement & {$redrawMoveArrows: RedrawMoveArrows}} */ (
|
|
1282
|
+
$e(arrayContents, '.arrayItems')
|
|
1283
|
+
).$redrawMoveArrows();
|
|
872
1284
|
}
|
|
873
1285
|
// Maybe not needed as removal would remove circular
|
|
874
|
-
Types.validateAllReferences({
|
|
1286
|
+
Types.validateAllReferences({
|
|
1287
|
+
// eslint-disable-next-line object-shorthand -- TS
|
|
1288
|
+
topRoot: /** @type {HTMLDivElement} */ (topRoot)
|
|
1289
|
+
});
|
|
875
1290
|
}}}, ['- Last item']],
|
|
876
1291
|
// We could only add this when there was more than one
|
|
877
1292
|
['button', {$on: {click () {
|
|
878
|
-
const arrayItems =
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
1293
|
+
const arrayItems =
|
|
1294
|
+
// eslint-disable-next-line max-len -- Long
|
|
1295
|
+
/** @type {HTMLDivElement & {$getPropertyInputs: GetPropertyInputs}} */ ($e(
|
|
1296
|
+
/** @type {Element} */ (
|
|
1297
|
+
/** @type {Element} */ (this).closest('.arrayContents')
|
|
1298
|
+
),
|
|
1299
|
+
'.arrayItems'
|
|
1300
|
+
));
|
|
882
1301
|
DOM.removeChildren(arrayItems);
|
|
883
1302
|
if (sparse) {
|
|
884
1303
|
decrementItemIndex(arrayItems);
|
|
@@ -886,10 +1305,102 @@ const arrayType = {
|
|
|
886
1305
|
itemIndex = -1;
|
|
887
1306
|
}
|
|
888
1307
|
// Maybe not needed as removal would remove circular
|
|
889
|
-
Types.validateAllReferences({
|
|
1308
|
+
Types.validateAllReferences({
|
|
1309
|
+
// eslint-disable-next-line object-shorthand -- TS
|
|
1310
|
+
topRoot: /** @type {HTMLDivElement} */ (topRoot)
|
|
1311
|
+
});
|
|
890
1312
|
}}}, ['x All']]
|
|
891
1313
|
]]
|
|
892
|
-
|
|
1314
|
+
);
|
|
1315
|
+
|
|
1316
|
+
const div = /** @type {HTMLDivElement} */ (
|
|
1317
|
+
jml('div', /** @type {import('jamilih').JamilihAttributes} */ ({
|
|
1318
|
+
dataset: {type},
|
|
1319
|
+
// is: 'array-or-object-editor',
|
|
1320
|
+
$custom: {
|
|
1321
|
+
// eslint-disable-next-line max-len -- Long
|
|
1322
|
+
/** @type {import('../formats/structuredCloning.js').AddAndSetArrayElement} */
|
|
1323
|
+
$addAndSetArrayElement ({
|
|
1324
|
+
propName, type, value, bringIntoFocus
|
|
1325
|
+
// , schemaContent, schemaState
|
|
1326
|
+
}) {
|
|
1327
|
+
this.$addArrayElement({propName});
|
|
1328
|
+
const typeChoices = this.$getTypeChoices();
|
|
1329
|
+
typeChoices.$setType({type, baseValue: value, bringIntoFocus});
|
|
1330
|
+
const root = typeChoices.$getTypeRoot();
|
|
1331
|
+
const typeObj = /** @type {import('../types.js').TypeObject} */ (
|
|
1332
|
+
Types.availableTypes[type]
|
|
1333
|
+
);
|
|
1334
|
+
if (typeObj.setValue) {
|
|
1335
|
+
typeObj.setValue({root, value});
|
|
1336
|
+
}
|
|
1337
|
+
Types.validate({type, root, topRoot});
|
|
1338
|
+
return root;
|
|
1339
|
+
},
|
|
1340
|
+
|
|
1341
|
+
/**
|
|
1342
|
+
* @typedef {() => Element} GetAddArrayElement
|
|
1343
|
+
*/
|
|
1344
|
+
|
|
1345
|
+
/** @type {GetAddArrayElement} */
|
|
1346
|
+
$getAddArrayElement () {
|
|
1347
|
+
const el = this
|
|
1348
|
+
.lastElementChild.firstElementChild.nextElementSibling;
|
|
1349
|
+
return sparse ? el.nextElementSibling : el;
|
|
1350
|
+
},
|
|
1351
|
+
/**
|
|
1352
|
+
* @type {AddArrayElement}
|
|
1353
|
+
* @this {HTMLDivElement & {
|
|
1354
|
+
* $getAddArrayElement: GetAddArrayElement
|
|
1355
|
+
* }}
|
|
1356
|
+
*/
|
|
1357
|
+
// @ts-ignore TS is apparently getting wrong $addArrayElement
|
|
1358
|
+
$addArrayElement ({propName, splice, alwaysFocus}) {
|
|
1359
|
+
const addArrayElement = this.$getAddArrayElement();
|
|
1360
|
+
/**
|
|
1361
|
+
* @type {HTMLButtonElement & {
|
|
1362
|
+
* $addArrayElement: AddArrayElement,
|
|
1363
|
+
* $getArrayItems: GetArrayItems
|
|
1364
|
+
* }}
|
|
1365
|
+
*/
|
|
1366
|
+
(addArrayElement).$addArrayElement({propName, splice, alwaysFocus});
|
|
1367
|
+
},
|
|
1368
|
+
$getArrayItems () {
|
|
1369
|
+
const addArrayElement = this.$getAddArrayElement();
|
|
1370
|
+
return addArrayElement.previousElementSibling;
|
|
1371
|
+
},
|
|
1372
|
+
$getTypeChoices () {
|
|
1373
|
+
const arrayItems = this.$getArrayItems();
|
|
1374
|
+
return $e(
|
|
1375
|
+
arrayItems.lastElementChild,
|
|
1376
|
+
`.typeChoices-${typeNamespace}`
|
|
1377
|
+
);
|
|
1378
|
+
}
|
|
1379
|
+
},
|
|
1380
|
+
$on: {
|
|
1381
|
+
click (ev) {
|
|
1382
|
+
const e = /** @type {Event} */ (ev);
|
|
1383
|
+
// eslint-disable-next-line prefer-destructuring -- TS
|
|
1384
|
+
const target = /** @type {HTMLInputElement} */ (e.target);
|
|
1385
|
+
|
|
1386
|
+
// We needed to stop preventing the default for the
|
|
1387
|
+
// invalid date checkbox; is this sufficient to prevent
|
|
1388
|
+
// other stray clicks apparently meant for the array
|
|
1389
|
+
// and object reference checking?
|
|
1390
|
+
if (target.type !== 'checkbox' && target.type !== 'radio') {
|
|
1391
|
+
e.preventDefault();
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
}), /** @type {import('jamilih').JamilihChildren} */ ([
|
|
1396
|
+
DOM.initialCaps(
|
|
1397
|
+
/** @type {import('../types.js').AvailableType} */
|
|
1398
|
+
(type)
|
|
1399
|
+
).replace(/s$/u, ''), nbsp.repeat(2),
|
|
1400
|
+
minusButton,
|
|
1401
|
+
arrayContents
|
|
1402
|
+
]))
|
|
1403
|
+
);
|
|
893
1404
|
topRoot = topRoot || div;
|
|
894
1405
|
return [div];
|
|
895
1406
|
}
|