@es-joy/jsoe 0.29.0 → 0.30.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/.claude/scheduled_tasks.lock +1 -0
- package/CHANGES.md +6 -0
- package/README.md +2 -0
- package/dist/fundamentalTypes/dateType.d.ts +8 -3
- package/dist/fundamentalTypes/dateType.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/search/fundamentalTypes/arraySearchType.d.ts +11 -4
- package/dist/search/fundamentalTypes/arraySearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/bigintSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/blobSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/dateSearchType.d.ts +8 -3
- package/dist/search/fundamentalTypes/dateSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/domexceptionSearchType.d.ts +5 -5
- package/dist/search/fundamentalTypes/domexceptionSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/enumSearchType.d.ts +4 -0
- package/dist/search/fundamentalTypes/enumSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/fileSearchType.d.ts +19 -10
- package/dist/search/fundamentalTypes/fileSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/filelistSearchType.d.ts +4 -12
- package/dist/search/fundamentalTypes/filelistSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/functionSearchType.d.ts +4 -4
- package/dist/search/fundamentalTypes/functionSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/mapSearchType.d.ts +8 -4
- package/dist/search/fundamentalTypes/mapSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/numberSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/objectSearchType.d.ts +10 -4
- package/dist/search/fundamentalTypes/objectSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/regexpSearchType.d.ts +7 -1
- package/dist/search/fundamentalTypes/regexpSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/setSearchType.d.ts +5 -4
- package/dist/search/fundamentalTypes/setSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/stringSearchType.d.ts +9 -1
- package/dist/search/fundamentalTypes/stringSearchType.d.ts.map +1 -1
- package/dist/search/fundamentalTypes/symbolSearchType.d.ts.map +1 -1
- package/dist/search/index.d.ts +18 -8
- package/dist/search/index.d.ts.map +1 -1
- package/dist/search/queryTree.d.ts +12 -1
- package/dist/search/queryTree.d.ts.map +1 -1
- package/dist/search/queryTreeBuilders.d.ts +6 -0
- package/dist/search/queryTreeBuilders.d.ts.map +1 -1
- package/dist/search/searchElementUtils.d.ts +17 -8
- package/dist/search/searchElementUtils.d.ts.map +1 -1
- package/dist/search/searchUtils.d.ts +343 -18
- package/dist/search/searchUtils.d.ts.map +1 -1
- package/dist/search/subTypes/blobHTMLSearchType.d.ts +22 -2
- package/dist/search/subTypes/blobHTMLSearchType.d.ts.map +1 -1
- package/dist/search/subTypes/recordSearchType.d.ts +4 -4
- package/dist/search/subTypes/recordSearchType.d.ts.map +1 -1
- package/dist/search/subTypes/tupleSearchType.d.ts +3 -3
- package/dist/search/subTypes/tupleSearchType.d.ts.map +1 -1
- package/dist/search/superTypes/buffersourceSearchType.d.ts.map +1 -1
- package/dist/search/unions/unionFamilySearchType.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/fundamentalTypes/dateType.js +9 -4
- package/src/fundamentalTypes/regexpType.js +1 -1
- package/src/jsoe.css +204 -0
- package/src/search/fundamentalTypes/arraySearchType.js +42 -7
- package/src/search/fundamentalTypes/bigintSearchType.js +7 -1
- package/src/search/fundamentalTypes/blobSearchType.js +2 -1
- package/src/search/fundamentalTypes/booleanSearchType.js +1 -1
- package/src/search/fundamentalTypes/dateSearchType.js +113 -20
- package/src/search/fundamentalTypes/domexceptionSearchType.js +39 -10
- package/src/search/fundamentalTypes/enumSearchType.js +5 -1
- package/src/search/fundamentalTypes/fileSearchType.js +64 -11
- package/src/search/fundamentalTypes/filelistSearchType.js +32 -7
- package/src/search/fundamentalTypes/functionSearchType.js +36 -12
- package/src/search/fundamentalTypes/mapSearchType.js +43 -13
- package/src/search/fundamentalTypes/numberSearchType.js +8 -1
- package/src/search/fundamentalTypes/objectSearchType.js +236 -17
- package/src/search/fundamentalTypes/regexpSearchType.js +29 -5
- package/src/search/fundamentalTypes/setSearchType.js +33 -7
- package/src/search/fundamentalTypes/stringSearchType.js +11 -2
- package/src/search/fundamentalTypes/symbolSearchType.js +2 -1
- package/src/search/index.js +26 -9
- package/src/search/queryTree.js +10 -1
- package/src/search/queryTreeBuilders.js +9 -0
- package/src/search/searchElementUtils.js +108 -24
- package/src/search/searchUtils.js +516 -24
- package/src/search/subTypes/blobHTMLSearchType.js +64 -7
- package/src/search/subTypes/recordSearchType.js +34 -13
- package/src/search/subTypes/tupleSearchType.js +51 -10
- package/src/search/superTypes/SpecialRealNumberSearchType.js +1 -1
- package/src/search/superTypes/buffersourceSearchType.js +7 -1
- package/src/search/unions/unionFamilySearchType.js +8 -0
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
buildPathLabel, findOwnControl, isExemptedByAncestorHasProperty
|
|
3
|
+
} from '../searchUtils.js';
|
|
2
4
|
import {makeBlobHTMLLeaf} from '../queryTreeBuilders.js';
|
|
3
5
|
import {getQueryViaElement} from '../searchElementUtils.js';
|
|
4
6
|
|
|
@@ -8,11 +10,31 @@ import {getQueryViaElement} from '../searchElementUtils.js';
|
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* Blob HTML: XPath, CSS selectors, full text search, regex search of raw
|
|
11
|
-
* HTML (README) - a mode `<select>` plus one
|
|
13
|
+
* HTML (README) - a mode `<select>` plus one value control, the same
|
|
12
14
|
* "pick a mode, give it one value" shape as `buildLiteralRegexControls`
|
|
13
15
|
* (`searchUtils.js`), but not built through it: the four modes and the
|
|
14
16
|
* `blobHTML` leaf kind they produce are specific to this one type, with no
|
|
15
|
-
* second caller to share the helper with.
|
|
17
|
+
* second caller to share the helper with. The value control is a single-line
|
|
18
|
+
* `<input>` for XPath/CSS-selector/regex, but swaps to a `<textarea>` for
|
|
19
|
+
* "Full text search" mode alone, since a search phrase in a body of text is
|
|
20
|
+
* the one mode actually expected to run to more than one line - both share
|
|
21
|
+
* the same class, so the mode `<select>`'s `change` handler (and `getQuery`)
|
|
22
|
+
* only need the tag name to tell them apart. Only the currently-visible one
|
|
23
|
+
* of the pair is ever `required` (toggled alongside `hidden` by the mode
|
|
24
|
+
* `change` handler): a `required` field that's merely hidden, rather than
|
|
25
|
+
* also un-required, still blocks the form's validity even though the user
|
|
26
|
+
* has no way to see or fill it.
|
|
27
|
+
*
|
|
28
|
+
* The `change` handler also checks `isExemptedByAncestorHasProperty` before
|
|
29
|
+
* (re-)asserting `required` on the now-visible control: nested as an
|
|
30
|
+
* optional object property's own child widget, an enclosing "Has property"
|
|
31
|
+
* already provides a complete constraint on its own (the same relief
|
|
32
|
+
* `setDescendantsRequired` gives other `required`-attribute controls), but
|
|
33
|
+
* that relief is a one-time toggle applied *before* `revalidateDescendants`
|
|
34
|
+
* re-dispatches a synthetic `change` on this very `<select>` - without this
|
|
35
|
+
* check, that synthetic event would immediately reassert `required` on
|
|
36
|
+
* whichever control the current mode makes visible, undoing the exemption
|
|
37
|
+
* `setDescendantsRequired` had just granted.
|
|
16
38
|
* @type {SearchTypeObject}
|
|
17
39
|
*/
|
|
18
40
|
const blobHTMLSearchType = {
|
|
@@ -29,8 +51,11 @@ const blobHTMLSearchType = {
|
|
|
29
51
|
const mode = /** @type {HTMLSelectElement|undefined} */ (
|
|
30
52
|
findOwnControl(this, 'select.jsoeSearchBlobHTMLMode')
|
|
31
53
|
)?.value;
|
|
32
|
-
const value = /** @type {HTMLInputElement|undefined} */ (
|
|
33
|
-
findOwnControl(
|
|
54
|
+
const value = /** @type {HTMLInputElement|HTMLTextAreaElement|undefined} */ (
|
|
55
|
+
findOwnControl(
|
|
56
|
+
this,
|
|
57
|
+
`${mode === 'fullText' ? 'textarea' : 'input'}.jsoeSearchBlobHTMLValue`
|
|
58
|
+
)
|
|
34
59
|
)?.value;
|
|
35
60
|
if (!value || !mode) {
|
|
36
61
|
return undefined;
|
|
@@ -46,7 +71,33 @@ const blobHTMLSearchType = {
|
|
|
46
71
|
['span', {class: 'searchLabel'}, [label]],
|
|
47
72
|
['label', [
|
|
48
73
|
'Mode: ',
|
|
49
|
-
['select', {
|
|
74
|
+
['select', {
|
|
75
|
+
name: `${name}-mode`,
|
|
76
|
+
class: 'jsoeSearchBlobHTMLMode',
|
|
77
|
+
$on: {
|
|
78
|
+
change () {
|
|
79
|
+
const container = this.closest('jsoe-search-blob-html');
|
|
80
|
+
const input = /** @type {HTMLInputElement|null|undefined} */ (
|
|
81
|
+
container?.querySelector('input.jsoeSearchBlobHTMLValue')
|
|
82
|
+
);
|
|
83
|
+
const textarea = /** @type {HTMLTextAreaElement|null|undefined} */ (
|
|
84
|
+
container?.querySelector('textarea.jsoeSearchBlobHTMLValue')
|
|
85
|
+
);
|
|
86
|
+
const isFullText = /** @type {HTMLSelectElement} */ (this).value ===
|
|
87
|
+
'fullText';
|
|
88
|
+
const exempted = container !== null &&
|
|
89
|
+
isExemptedByAncestorHasProperty(container);
|
|
90
|
+
if (input) {
|
|
91
|
+
input.hidden = isFullText;
|
|
92
|
+
input.required = !isFullText && !exempted;
|
|
93
|
+
}
|
|
94
|
+
if (textarea) {
|
|
95
|
+
textarea.hidden = !isFullText;
|
|
96
|
+
textarea.required = isFullText && !exempted;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}, [
|
|
50
101
|
['option', {value: 'xpath'}, ['XPath']],
|
|
51
102
|
['option', {value: 'cssSelector'}, ['CSS selector']],
|
|
52
103
|
['option', {value: 'fullText'}, ['Full text search']],
|
|
@@ -55,7 +106,13 @@ const blobHTMLSearchType = {
|
|
|
55
106
|
]],
|
|
56
107
|
['label', [
|
|
57
108
|
'Value: ',
|
|
58
|
-
['input', {
|
|
109
|
+
['input', {
|
|
110
|
+
type: 'text', name: `${name}-value`, class: 'jsoeSearchBlobHTMLValue',
|
|
111
|
+
required: true
|
|
112
|
+
}],
|
|
113
|
+
['textarea', {
|
|
114
|
+
name: `${name}-value`, class: 'jsoeSearchBlobHTMLValue', hidden: true
|
|
115
|
+
}]
|
|
59
116
|
]]
|
|
60
117
|
]];
|
|
61
118
|
},
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
buildPathLabel, buildCheckbox, readCheckbox, buildOptInFieldset,
|
|
3
|
+
readOptInChecked, wireOptInFieldset, buildAtLeastOneSentinel, syncAtLeastOneCheck
|
|
4
|
+
} from '../searchUtils.js';
|
|
2
5
|
import {makeMapRecordJointLeaf} from '../queryTreeBuilders.js';
|
|
3
6
|
import {findSearchElement, getQueryViaElement, hasGetQuery} from '../searchElementUtils.js';
|
|
4
7
|
import {buildSearchWidget} from '../searchDispatch.js';
|
|
@@ -7,6 +10,16 @@ import {buildSearchWidget} from '../searchDispatch.js';
|
|
|
7
10
|
* @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
|
|
8
11
|
*/
|
|
9
12
|
|
|
13
|
+
/**
|
|
14
|
+
* @param {Element} root - a `jsoe-search-record` element
|
|
15
|
+
* @returns {void}
|
|
16
|
+
*/
|
|
17
|
+
function syncKeyValueValidity (root) {
|
|
18
|
+
syncAtLeastOneCheck(
|
|
19
|
+
root, () => readOptInChecked(root, 'key') || readOptInChecked(root, 'value')
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
10
23
|
/**
|
|
11
24
|
* Record search is "key-schema search AND/OR value-schema search,"
|
|
12
25
|
* structurally unlike object's additive "has property" (search plan §1) -
|
|
@@ -15,7 +28,10 @@ import {buildSearchWidget} from '../searchDispatch.js';
|
|
|
15
28
|
* whether a match must come from the *same* entry ("has key 2-4 and value
|
|
16
29
|
* 7-9", README) via the "joint" toggle on the resulting `mapRecordJoint`
|
|
17
30
|
* leaf - also used for `looseRecord`, aliased to this same module in
|
|
18
|
-
* `searchDispatch.js` since the search semantics are identical.
|
|
31
|
+
* `searchDispatch.js` since the search semantics are identical. Key and
|
|
32
|
+
* value each get their own `buildOptInFieldset` (see `mapSearchType.js`'s
|
|
33
|
+
* matching doc for why), but leaving *both* unopted-in is itself invalid via
|
|
34
|
+
* `buildAtLeastOneSentinel`.
|
|
19
35
|
* @type {SearchTypeObject}
|
|
20
36
|
*/
|
|
21
37
|
const recordSearchType = {
|
|
@@ -47,15 +63,21 @@ const recordSearchType = {
|
|
|
47
63
|
dataset: {searchPath: path, searchKind: 'record'},
|
|
48
64
|
title: label,
|
|
49
65
|
$define: {
|
|
66
|
+
/** @this {HTMLElement} */
|
|
67
|
+
connectedCallback () {
|
|
68
|
+
wireOptInFieldset(this, 'key', () => syncKeyValueValidity(this));
|
|
69
|
+
wireOptInFieldset(this, 'value', () => syncKeyValueValidity(this));
|
|
70
|
+
syncKeyValueValidity(this);
|
|
71
|
+
},
|
|
50
72
|
/** @this {HTMLElement} */
|
|
51
73
|
getQuery () {
|
|
52
74
|
const searchPath = this.dataset.searchPath ?? '';
|
|
53
75
|
const keyEl = findSearchElement(this, `${searchPath}/*key`);
|
|
54
76
|
const valueEl = findSearchElement(this, `${searchPath}/*value`);
|
|
55
|
-
const keyQuery = keyEl && hasGetQuery(keyEl)
|
|
77
|
+
const keyQuery = keyEl && hasGetQuery(keyEl) && readOptInChecked(this, 'key')
|
|
56
78
|
? keyEl.getQuery()
|
|
57
79
|
: undefined;
|
|
58
|
-
const valueQuery = valueEl && hasGetQuery(valueEl)
|
|
80
|
+
const valueQuery = valueEl && hasGetQuery(valueEl) && readOptInChecked(this, 'value')
|
|
59
81
|
? valueEl.getQuery()
|
|
60
82
|
: undefined;
|
|
61
83
|
if (!keyQuery && !valueQuery) {
|
|
@@ -67,15 +89,14 @@ const recordSearchType = {
|
|
|
67
89
|
}
|
|
68
90
|
}, [
|
|
69
91
|
['span', {class: 'searchLabel'}, [label]],
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
buildCheckbox({name: `${name}-joint`, label: 'Require same entry'})
|
|
92
|
+
...buildOptInFieldset({
|
|
93
|
+
name: `${name}-key`, key: 'key', label: 'Key matches', children: [keyArr]
|
|
94
|
+
}),
|
|
95
|
+
...buildOptInFieldset({
|
|
96
|
+
name: `${name}-value`, key: 'value', label: 'Value matches', children: [valueArr]
|
|
97
|
+
}),
|
|
98
|
+
buildCheckbox({name: `${name}-joint`, label: 'Require same entry'}),
|
|
99
|
+
buildAtLeastOneSentinel()
|
|
79
100
|
]];
|
|
80
101
|
},
|
|
81
102
|
getQuery: getQueryViaElement
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
buildPathLabel, buildLengthSizeControls, readLengthSizeQuery,
|
|
3
|
+
buildOptInFieldset, readOptInChecked, wireOptInFieldset,
|
|
4
|
+
buildAtLeastOneSentinel, syncAtLeastOneCheck
|
|
5
|
+
} from '../searchUtils.js';
|
|
2
6
|
import {combineAnd} from '../queryTreeBuilders.js';
|
|
3
7
|
import {findSearchElement, getQueryViaElement, hasGetQuery} from '../searchElementUtils.js';
|
|
4
8
|
import {buildSearchWidget} from '../searchDispatch.js';
|
|
@@ -7,6 +11,21 @@ import {buildSearchWidget} from '../searchDispatch.js';
|
|
|
7
11
|
* @typedef {import('../searchDispatch.js').SearchTypeObject} SearchTypeObject
|
|
8
12
|
*/
|
|
9
13
|
|
|
14
|
+
/**
|
|
15
|
+
* @param {Element} root - a `jsoe-search-tuple` element
|
|
16
|
+
* @returns {void}
|
|
17
|
+
*/
|
|
18
|
+
function syncTupleValidity (root) {
|
|
19
|
+
const itemCount = Number(/** @type {HTMLElement} */ (root).dataset.itemCount ?? '0');
|
|
20
|
+
const hasRest = /** @type {HTMLElement} */ (root).dataset.hasRest === 'true';
|
|
21
|
+
syncAtLeastOneCheck(root, () => (
|
|
22
|
+
Array.from({length: itemCount}, (_, idx) => String(idx)).some(
|
|
23
|
+
(key) => readOptInChecked(root, key)
|
|
24
|
+
) ||
|
|
25
|
+
(hasRest && (readOptInChecked(root, 'rest') || readLengthSizeQuery(root, '') !== undefined))
|
|
26
|
+
));
|
|
27
|
+
}
|
|
28
|
+
|
|
10
29
|
/**
|
|
11
30
|
* Each fixed position gets its own control from `.items[i]`, not one
|
|
12
31
|
* control repeated per element (search plan §1 - unlike the value-editing
|
|
@@ -19,6 +38,9 @@ import {buildSearchWidget} from '../searchDispatch.js';
|
|
|
19
38
|
* items.length`, no sparse toggle - not applicable to a tuple), and the
|
|
20
39
|
* `rest` element itself recurses into its own search widget under the same
|
|
21
40
|
* `*` path-segment convention `arraySearchType.js` uses for its element.
|
|
41
|
+
* Leaving every position, the rest element, and (when present) the length
|
|
42
|
+
* unconfigured at once is invalid (`buildAtLeastOneSentinel`), the same as
|
|
43
|
+
* `arraySearchType.js`/`setSearchType.js`/`filelistSearchType.js`.
|
|
22
44
|
* @type {SearchTypeObject}
|
|
23
45
|
*/
|
|
24
46
|
const tupleSearchType = {
|
|
@@ -54,22 +76,24 @@ const tupleSearchType = {
|
|
|
54
76
|
/** @type {import('../../types.js').JamilihArray[]} */
|
|
55
77
|
const children = [['span', {class: 'searchLabel'}, [label]]];
|
|
56
78
|
itemArrs.forEach((itemArr, idx) => {
|
|
57
|
-
children.push(
|
|
58
|
-
|
|
59
|
-
itemArr
|
|
60
|
-
|
|
79
|
+
children.push(...buildOptInFieldset({
|
|
80
|
+
name: `${name}-${idx}`, key: String(idx), label: `Position ${idx} matches`,
|
|
81
|
+
children: [itemArr]
|
|
82
|
+
}));
|
|
61
83
|
});
|
|
62
84
|
if (rest) {
|
|
85
|
+
const restChild = /** @type {import('../../types.js').JamilihArray} */ (restArr);
|
|
63
86
|
children.push(
|
|
64
87
|
...buildLengthSizeControls({
|
|
65
88
|
name, min: items.length, max: undefined, includeSparse: false
|
|
66
89
|
}),
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
90
|
+
...buildOptInFieldset({
|
|
91
|
+
name: `${name}-rest`, key: 'rest', label: 'Rest element matches',
|
|
92
|
+
children: [restChild]
|
|
93
|
+
})
|
|
71
94
|
);
|
|
72
95
|
}
|
|
96
|
+
children.push(buildAtLeastOneSentinel());
|
|
73
97
|
|
|
74
98
|
return ['jsoe-search-tuple', {
|
|
75
99
|
dataset: {
|
|
@@ -84,11 +108,28 @@ const tupleSearchType = {
|
|
|
84
108
|
// defined, so a second tuple widget on the same page would
|
|
85
109
|
// otherwise silently reuse the first tuple's item count/rest-ness.
|
|
86
110
|
/** @this {HTMLElement} */
|
|
111
|
+
connectedCallback () {
|
|
112
|
+
const itemCount = Number(this.dataset.itemCount ?? '0');
|
|
113
|
+
Array.from({length: itemCount}, (_, idx) => String(idx)).forEach(
|
|
114
|
+
(key) => wireOptInFieldset(this, key, () => syncTupleValidity(this))
|
|
115
|
+
);
|
|
116
|
+
if (this.dataset.hasRest === 'true') {
|
|
117
|
+
wireOptInFieldset(this, 'rest', () => syncTupleValidity(this));
|
|
118
|
+
this.querySelector('input.jsoeSearchSize')?.addEventListener(
|
|
119
|
+
'input', () => syncTupleValidity(this)
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
syncTupleValidity(this);
|
|
123
|
+
},
|
|
124
|
+
/** @this {HTMLElement} */
|
|
87
125
|
getQuery () {
|
|
88
126
|
const searchPath = this.dataset.searchPath ?? '';
|
|
89
127
|
const itemCount = Number(this.dataset.itemCount ?? '0');
|
|
90
128
|
const hasRest = this.dataset.hasRest === 'true';
|
|
91
129
|
const itemLeaves = Array.from({length: itemCount}, (_, idx) => {
|
|
130
|
+
if (!readOptInChecked(this, String(idx))) {
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
92
133
|
const itemEl = findSearchElement(this, `${searchPath}/${idx}`);
|
|
93
134
|
return itemEl && hasGetQuery(itemEl) ? itemEl.getQuery() : undefined;
|
|
94
135
|
});
|
|
@@ -97,7 +138,7 @@ const tupleSearchType = {
|
|
|
97
138
|
}
|
|
98
139
|
const lengthLeaf = readLengthSizeQuery(this, searchPath);
|
|
99
140
|
const restEl = findSearchElement(this, `${searchPath}/*`);
|
|
100
|
-
const restLeaf = restEl && hasGetQuery(restEl)
|
|
141
|
+
const restLeaf = restEl && hasGetQuery(restEl) && readOptInChecked(this, 'rest')
|
|
101
142
|
? restEl.getQuery()
|
|
102
143
|
: undefined;
|
|
103
144
|
return combineAnd([...itemLeaves, lengthLeaf, restLeaf]);
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
buildPathLabel, buildRangeInputsPair, readRangeInputsPair, syncRangeValidity
|
|
3
|
+
} from '../searchUtils.js';
|
|
2
4
|
import {makeRangeLeaf} from '../queryTreeBuilders.js';
|
|
3
5
|
import {getQueryViaElement} from '../searchElementUtils.js';
|
|
4
6
|
|
|
@@ -24,6 +26,10 @@ const buffersourceSearchType = {
|
|
|
24
26
|
dataset: {searchPath: path, searchKind: 'buffersource'},
|
|
25
27
|
title: label,
|
|
26
28
|
$define: {
|
|
29
|
+
/** @this {HTMLElement} */
|
|
30
|
+
connectedCallback () {
|
|
31
|
+
syncRangeValidity(this);
|
|
32
|
+
},
|
|
27
33
|
/** @this {HTMLElement} */
|
|
28
34
|
getQuery () {
|
|
29
35
|
const {gte, lte} = readRangeInputsPair(this);
|
|
@@ -110,6 +110,14 @@ export function makeUnionFamilySearchType ({tagName, discriminated}) {
|
|
|
110
110
|
['select', {
|
|
111
111
|
name,
|
|
112
112
|
class: 'jsoeSearchTypeOf',
|
|
113
|
+
// The "(any)" placeholder's `value: ''` below is exactly what
|
|
114
|
+
// native `required` treats as "nothing selected", so choosing
|
|
115
|
+
// any real branch already satisfies it - no custom validity
|
|
116
|
+
// code needed. A union/xor/discriminatedUnion has no other
|
|
117
|
+
// possible constraint (unlike `mapSearchType.js`'s key/value or
|
|
118
|
+
// `objectSearchType.js`'s properties), so this alone is "no
|
|
119
|
+
// absent values" for the whole widget, not just one facet of it.
|
|
120
|
+
required: true,
|
|
113
121
|
$on: {
|
|
114
122
|
change () {
|
|
115
123
|
if (!isSelectElement(this)) {
|