@optionfactory/fml 9.0.0-rc10 → 9.0.0-rc11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/custom-elements.json +213 -13
- package/dist/fml.css +6 -5
- package/dist/fml.css.map +1 -1
- package/dist/fml.iife.js +183 -35
- package/dist/fml.iife.js.map +1 -1
- package/dist/fml.iife.min.js +1 -1
- package/dist/fml.iife.min.js.map +1 -1
- package/dist/ful.css +6 -5
- package/dist/ful.css.map +1 -1
- package/dist/ful.d.mts +27 -1
- package/dist/ful.iife.js +182 -35
- package/dist/ful.iife.js.map +1 -1
- package/dist/ful.iife.min.js +1 -1
- package/dist/ful.iife.min.js.map +1 -1
- package/dist/ful.min.mjs +1 -1
- package/dist/ful.min.mjs.map +1 -1
- package/dist/ful.mjs +182 -36
- package/dist/ful.mjs.map +1 -1
- package/dist/vscode.html-custom-data.json +94 -12
- package/dist/web-types.json +213 -14
- package/package.json +1 -1
package/dist/fml.iife.js
CHANGED
|
@@ -7636,6 +7636,22 @@ var fml = (function (exports) {
|
|
|
7636
7636
|
*/
|
|
7637
7637
|
const inheritedAutocomplete = (el) => el.closest('form')?.getAttribute('autocomplete') ?? null;
|
|
7638
7638
|
|
|
7639
|
+
/** Rendering a text input is what costs these the native min/max/step enforcement. */
|
|
7640
|
+
const INPUT_MODES = { numeric: 'numeric', decimal: 'decimal' };
|
|
7641
|
+
|
|
7642
|
+
const signed = (v, digits) => (v.startsWith('-') ? '-' : '') + digits(v);
|
|
7643
|
+
|
|
7644
|
+
const NUMERIC_FILTERS = {
|
|
7645
|
+
numeric: (v) => signed(v, (t) => t.replace(/\D/g, '')),
|
|
7646
|
+
//one separator, the first: the rest are a slip while typing, not a value
|
|
7647
|
+
decimal: (v) =>
|
|
7648
|
+
signed(v, (t) => {
|
|
7649
|
+
const kept = t.replace(/[^\d.,]/g, '');
|
|
7650
|
+
const at = kept.search(/[.,]/);
|
|
7651
|
+
return at === -1 ? kept : kept.slice(0, at + 1) + kept.slice(at + 1).replace(/[.,]/g, '');
|
|
7652
|
+
}),
|
|
7653
|
+
};
|
|
7654
|
+
|
|
7639
7655
|
const warnedBoth = new WeakSet();
|
|
7640
7656
|
const filterOf = (el) => {
|
|
7641
7657
|
const keep = el.declared('keep');
|
|
@@ -7655,7 +7671,7 @@ var fml = (function (exports) {
|
|
|
7655
7671
|
const re = compiled('reject', reject);
|
|
7656
7672
|
return re && ((v) => v.replace(re, ''));
|
|
7657
7673
|
}
|
|
7658
|
-
return null;
|
|
7674
|
+
return NUMERIC_FILTERS[el._type()] ?? null;
|
|
7659
7675
|
};
|
|
7660
7676
|
|
|
7661
7677
|
/** A labelled text input over any native type or textarea; the temporal inputs are its subclasses. */
|
|
@@ -7691,9 +7707,17 @@ var fml = (function (exports) {
|
|
|
7691
7707
|
return this.declared('type') ?? (this.declared('v-type') === 'number' ? 'number' : 'text');
|
|
7692
7708
|
}
|
|
7693
7709
|
_build({ slots }) {
|
|
7694
|
-
const
|
|
7710
|
+
const declared = this._type();
|
|
7711
|
+
const mode = INPUT_MODES[declared];
|
|
7712
|
+
//a numeric widget is a text input: the type names the keyboard, not the
|
|
7713
|
+
//control, so the rendered markup stays valid html
|
|
7714
|
+
const type = mode ? 'text' : declared;
|
|
7695
7715
|
const fragment = this.template().withOverlay({ type, slots }).render();
|
|
7696
7716
|
this._input = fragment.querySelector('input,textarea');
|
|
7717
|
+
if (mode) {
|
|
7718
|
+
//before the passthrough, which stays the last word
|
|
7719
|
+
Attributes.set(this._input, 'inputmode', mode);
|
|
7720
|
+
}
|
|
7697
7721
|
|
|
7698
7722
|
//the browser reads autocomplete off the control it is classifying, so the
|
|
7699
7723
|
//field's own token, or the form's where it declares none, is put there.
|
|
@@ -7745,13 +7769,15 @@ var fml = (function (exports) {
|
|
|
7745
7769
|
if (trimmed === '') {
|
|
7746
7770
|
return null;
|
|
7747
7771
|
}
|
|
7772
|
+
//the wire carries a dot wherever the comma is what the keyboard shows
|
|
7773
|
+
const normalized = this._type() === 'decimal' ? trimmed.replaceAll(',', '.') : trimmed;
|
|
7748
7774
|
if (this.declared('v-type') === 'number') {
|
|
7749
7775
|
//typed values are an explicit opt in, as the select's k-type: blank
|
|
7750
7776
|
//stays null, and a value that does not decode is kept as it is
|
|
7751
|
-
const n = Number(
|
|
7752
|
-
return Number.isNaN(n) ?
|
|
7777
|
+
const n = Number(normalized);
|
|
7778
|
+
return Number.isNaN(n) ? normalized : n;
|
|
7753
7779
|
}
|
|
7754
|
-
return
|
|
7780
|
+
return normalized;
|
|
7755
7781
|
}
|
|
7756
7782
|
set value(value) {
|
|
7757
7783
|
this._input.value = value === '' || value === undefined ? null : value;
|
|
@@ -8743,10 +8769,27 @@ var fml = (function (exports) {
|
|
|
8743
8769
|
method: el.declared('method') ?? 'POST',
|
|
8744
8770
|
mode: el.declared('mode'),
|
|
8745
8771
|
prefetch: el.declared('preload'),
|
|
8746
|
-
revision: el
|
|
8772
|
+
revision: SelectLoader.#revisionFrom(el),
|
|
8747
8773
|
responseMapper: SelectLoader.#responseMapperFrom(el),
|
|
8748
8774
|
});
|
|
8749
8775
|
}
|
|
8776
|
+
static #revisionFrom(el) {
|
|
8777
|
+
const declared = el.declared('revision');
|
|
8778
|
+
if (declared !== '') {
|
|
8779
|
+
return declared;
|
|
8780
|
+
}
|
|
8781
|
+
const configured = el.component('revision');
|
|
8782
|
+
if (configured === undefined || configured === null) {
|
|
8783
|
+
//not caching while the markup says to cache is the quiet failure
|
|
8784
|
+
//this branch exists to make loud
|
|
8785
|
+
console.warn(
|
|
8786
|
+
"a valueless revision asks the registry for one, and no 'revision' component is defined: the vocabulary will not be cached",
|
|
8787
|
+
el,
|
|
8788
|
+
);
|
|
8789
|
+
return null;
|
|
8790
|
+
}
|
|
8791
|
+
return typeof configured === 'function' ? configured() : configured;
|
|
8792
|
+
}
|
|
8750
8793
|
static #responseMapperFrom(el) {
|
|
8751
8794
|
if (el.declared('k-expr') && el.declared('l-expr')) {
|
|
8752
8795
|
return (response) => {
|
|
@@ -8779,7 +8822,7 @@ var fml = (function (exports) {
|
|
|
8779
8822
|
static slots = true;
|
|
8780
8823
|
static template = `
|
|
8781
8824
|
<ful-spinner class="centered" role="status" hidden><span class="ful-sr-only">{{ #l10n:t('spinner.loading') }}</span></ful-spinner>
|
|
8782
|
-
<
|
|
8825
|
+
<ful-empty data-ref="empty" aria-live="polite" hidden>{{ #l10n:t('dropdown.empty') }}</ful-empty>
|
|
8783
8826
|
<menu tabindex="-1" role="listbox" hidden></menu>
|
|
8784
8827
|
`;
|
|
8785
8828
|
static templates = {
|
|
@@ -8801,7 +8844,7 @@ var fml = (function (exports) {
|
|
|
8801
8844
|
? this.template('options')
|
|
8802
8845
|
: Templates.fromFragment(slots.default);
|
|
8803
8846
|
this.#spinner = fragment.querySelector('ful-spinner');
|
|
8804
|
-
this.#empty = fragment.querySelector('
|
|
8847
|
+
this.#empty = fragment.querySelector('[data-ref=empty]');
|
|
8805
8848
|
this.#menu = fragment.querySelector('menu');
|
|
8806
8849
|
//the listbox is named so a combobox can point aria-controls and
|
|
8807
8850
|
//aria-activedescendant at it: a reference to an unnamed element resolves
|
|
@@ -9161,7 +9204,7 @@ var fml = (function (exports) {
|
|
|
9161
9204
|
return;
|
|
9162
9205
|
}
|
|
9163
9206
|
this.#abortdload();
|
|
9164
|
-
this.#close();
|
|
9207
|
+
this.#close(true);
|
|
9165
9208
|
});
|
|
9166
9209
|
this.#input.addEventListener('keydown', (e) => {
|
|
9167
9210
|
if (!this._interactive()) {
|
|
@@ -9194,7 +9237,6 @@ var fml = (function (exports) {
|
|
|
9194
9237
|
this.#editing = false;
|
|
9195
9238
|
this.#values.set(this.#coerceKey(e.detail.entry.key), e.detail.entry);
|
|
9196
9239
|
this.#changed();
|
|
9197
|
-
this.#syncBadges();
|
|
9198
9240
|
this.#input.focus();
|
|
9199
9241
|
this.#ddmenu.hide();
|
|
9200
9242
|
if (!this.#multiple) {
|
|
@@ -9251,7 +9293,6 @@ var fml = (function (exports) {
|
|
|
9251
9293
|
}
|
|
9252
9294
|
this.#values.delete(key);
|
|
9253
9295
|
this.#changed();
|
|
9254
|
-
this.#syncBadges();
|
|
9255
9296
|
}
|
|
9256
9297
|
#chipKeydown(e, badge) {
|
|
9257
9298
|
switch (e.code) {
|
|
@@ -9347,7 +9388,7 @@ var fml = (function (exports) {
|
|
|
9347
9388
|
}
|
|
9348
9389
|
case 'Tab': {
|
|
9349
9390
|
this.#abortdload();
|
|
9350
|
-
this.#close();
|
|
9391
|
+
this.#close(true);
|
|
9351
9392
|
break;
|
|
9352
9393
|
}
|
|
9353
9394
|
}
|
|
@@ -9363,12 +9404,25 @@ var fml = (function (exports) {
|
|
|
9363
9404
|
}
|
|
9364
9405
|
return;
|
|
9365
9406
|
}
|
|
9366
|
-
this.#
|
|
9367
|
-
this.#ddmenu.moveOrShow(forward, () => this.#loader.load(this.#input.value), [...this.#values.keys()]);
|
|
9407
|
+
this.#ddmenu.moveOrShow(forward, () => this.#loader.load(this.#query()), [...this.#values.keys()]);
|
|
9368
9408
|
}
|
|
9369
|
-
|
|
9409
|
+
/**
|
|
9410
|
+
* @param commit whether the user is leaving the field, which only a blur or
|
|
9411
|
+
* a Tab is: Escape cancels, and closing the list or a claim landing leaves
|
|
9412
|
+
* the edit in progress
|
|
9413
|
+
*/
|
|
9414
|
+
#close(commit = false) {
|
|
9370
9415
|
this.#ddmenu.hide();
|
|
9416
|
+
//emptying the box and leaving is a clear: redisplaying the label would
|
|
9417
|
+
//discard the edit without a word. A multiple select keeps its box empty
|
|
9418
|
+
//by design, so only a single one can mean it
|
|
9419
|
+
const cleared =
|
|
9420
|
+
commit && this.#editing && !this.#multiple && this.#input.value === '' && this.#values.size !== 0;
|
|
9371
9421
|
this.#editing = false;
|
|
9422
|
+
if (cleared) {
|
|
9423
|
+
this.#values.clear();
|
|
9424
|
+
this.#changed();
|
|
9425
|
+
}
|
|
9372
9426
|
this.#display();
|
|
9373
9427
|
}
|
|
9374
9428
|
/**
|
|
@@ -9377,14 +9431,15 @@ var fml = (function (exports) {
|
|
|
9377
9431
|
* highlighted.
|
|
9378
9432
|
*/
|
|
9379
9433
|
#open() {
|
|
9380
|
-
this.#
|
|
9381
|
-
return this.#ddmenu.show(() => this.#loader.load(this.#input.value), [...this.#values.keys()]);
|
|
9434
|
+
return this.#ddmenu.show(() => this.#loader.load(this.#query()), [...this.#values.keys()]);
|
|
9382
9435
|
}
|
|
9383
|
-
|
|
9384
|
-
|
|
9385
|
-
|
|
9386
|
-
|
|
9387
|
-
|
|
9436
|
+
/**
|
|
9437
|
+
* Browsing is the whole vocabulary, not the label already chosen, and the
|
|
9438
|
+
* label stays on screen while it happens: a select showing nothing reads as
|
|
9439
|
+
* an empty one.
|
|
9440
|
+
*/
|
|
9441
|
+
#query() {
|
|
9442
|
+
return this.#editing ? this.#input.value : '';
|
|
9388
9443
|
}
|
|
9389
9444
|
#display() {
|
|
9390
9445
|
const entry = this.#values.values().next().value;
|
|
@@ -9395,6 +9450,9 @@ var fml = (function (exports) {
|
|
|
9395
9450
|
return [...this.#values.values()];
|
|
9396
9451
|
}
|
|
9397
9452
|
#changed() {
|
|
9453
|
+
//settled before the event: a listener reading the control during it has to
|
|
9454
|
+
//see the selection that caused it
|
|
9455
|
+
this.#syncBadges();
|
|
9398
9456
|
//the detail carries the keys the value property answers with, as every
|
|
9399
9457
|
//other field's does, and the labeled selection beside them
|
|
9400
9458
|
this._notifyChange({ entry: this.entry });
|
|
@@ -10041,6 +10099,7 @@ var fml = (function (exports) {
|
|
|
10041
10099
|
static slots = true;
|
|
10042
10100
|
static config = {
|
|
10043
10101
|
searchIcon: 'search',
|
|
10102
|
+
emptyIcon: 'inbox',
|
|
10044
10103
|
};
|
|
10045
10104
|
static template = `
|
|
10046
10105
|
<ful-form data-tpl-if="slots.filters">
|
|
@@ -10054,10 +10113,21 @@ var fml = (function (exports) {
|
|
|
10054
10113
|
<tbody data-ref="initial">
|
|
10055
10114
|
<tr>
|
|
10056
10115
|
<td data-tpl-colspan="schema.length">
|
|
10057
|
-
<
|
|
10058
|
-
<
|
|
10116
|
+
<ful-empty>
|
|
10117
|
+
<ful-icon data-tpl-if="config.searchIcon" data-tpl-name="config.searchIcon" aria-hidden="true"></ful-icon>
|
|
10059
10118
|
{{ #l10n:t('table.initial') }}
|
|
10060
|
-
</
|
|
10119
|
+
</ful-empty>
|
|
10120
|
+
</td>
|
|
10121
|
+
</tr>
|
|
10122
|
+
</tbody>
|
|
10123
|
+
<tbody data-ref="empty" hidden>
|
|
10124
|
+
<tr>
|
|
10125
|
+
<td data-tpl-colspan="schema.length">
|
|
10126
|
+
<ful-empty data-tpl-if="slots.empty">{{{{ slots.empty }}}}</ful-empty>
|
|
10127
|
+
<ful-empty data-tpl-if="!slots.empty">
|
|
10128
|
+
<ful-icon data-tpl-if="config.emptyIcon" data-tpl-name="config.emptyIcon" aria-hidden="true"></ful-icon>
|
|
10129
|
+
{{ #l10n:t('table.no-data') }}
|
|
10130
|
+
</ful-empty>
|
|
10061
10131
|
</td>
|
|
10062
10132
|
</tr>
|
|
10063
10133
|
</tbody>
|
|
@@ -10087,11 +10157,6 @@ var fml = (function (exports) {
|
|
|
10087
10157
|
`;
|
|
10088
10158
|
static templates = {
|
|
10089
10159
|
row: `
|
|
10090
|
-
<tr data-tpl-if="pageResponse.data.length == 0">
|
|
10091
|
-
<td data-tpl-colspan="schema.length">
|
|
10092
|
-
{{ #l10n:t('table.no-data') }}
|
|
10093
|
-
</td>
|
|
10094
|
-
</tr>
|
|
10095
10160
|
{{{{ schema.rowsTemplate.withOverlay({'rows': pageResponse.data}).render() }}}}
|
|
10096
10161
|
`,
|
|
10097
10162
|
};
|
|
@@ -10100,6 +10165,7 @@ var fml = (function (exports) {
|
|
|
10100
10165
|
#body;
|
|
10101
10166
|
#loading;
|
|
10102
10167
|
#noAutoload;
|
|
10168
|
+
#empty;
|
|
10103
10169
|
#feedback;
|
|
10104
10170
|
#paginator;
|
|
10105
10171
|
#sorters;
|
|
@@ -10150,6 +10216,7 @@ var fml = (function (exports) {
|
|
|
10150
10216
|
this.#body = table.querySelector(':scope > tbody');
|
|
10151
10217
|
this.#loading = table.querySelector(':scope > tbody[data-ref=loading]');
|
|
10152
10218
|
this.#noAutoload = table.querySelector(':scope > tbody[data-ref=initial]');
|
|
10219
|
+
this.#empty = table.querySelector(':scope > tbody[data-ref=empty]');
|
|
10153
10220
|
this.#feedback = table.querySelector(':scope > tbody[data-ref=feedback]');
|
|
10154
10221
|
this.#paginator = Nodes.queryChildren(fragment, 'ful-pagination');
|
|
10155
10222
|
this.replaceChildren(fragment);
|
|
@@ -10240,6 +10307,7 @@ var fml = (function (exports) {
|
|
|
10240
10307
|
this.#loading.toggleAttribute('hidden', this.#body.childElementCount > 0);
|
|
10241
10308
|
this.#feedback.setAttribute('hidden', '');
|
|
10242
10309
|
this.#noAutoload.setAttribute('hidden', '');
|
|
10310
|
+
this.#empty.setAttribute('hidden', '');
|
|
10243
10311
|
this.setAttribute('aria-busy', 'true');
|
|
10244
10312
|
try {
|
|
10245
10313
|
const pageResponse = await this.#loader.load(pageRequest, sortRequest, filterRequest);
|
|
@@ -10248,6 +10316,16 @@ var fml = (function (exports) {
|
|
|
10248
10316
|
}
|
|
10249
10317
|
this.#latestRequest = { pageRequest, sortRequest, filterRequest };
|
|
10250
10318
|
this.#update(pageRequest, sortRequest, filterRequest, pageResponse);
|
|
10319
|
+
//settled before the event: a listener counting what loaded has to
|
|
10320
|
+
//see the table as it now is
|
|
10321
|
+
this.removeAttribute('aria-busy');
|
|
10322
|
+
this.dispatchEvent(
|
|
10323
|
+
new CustomEvent('load:success', {
|
|
10324
|
+
bubbles: true,
|
|
10325
|
+
cancelable: false,
|
|
10326
|
+
detail: { pageRequest, sortRequest, filterRequest, response: pageResponse },
|
|
10327
|
+
}),
|
|
10328
|
+
);
|
|
10251
10329
|
} catch (/** @type any */ error) {
|
|
10252
10330
|
if (claim.stale) {
|
|
10253
10331
|
//the newer load owns the table and its outcome: a superseded
|
|
@@ -10264,12 +10342,15 @@ var fml = (function (exports) {
|
|
|
10264
10342
|
error,
|
|
10265
10343
|
`${error}`,
|
|
10266
10344
|
);
|
|
10345
|
+
this.removeAttribute('aria-busy');
|
|
10346
|
+
this.dispatchEvent(
|
|
10347
|
+
new CustomEvent('load:failure', {
|
|
10348
|
+
bubbles: true,
|
|
10349
|
+
cancelable: false,
|
|
10350
|
+
detail: { pageRequest, sortRequest, filterRequest, exception: error },
|
|
10351
|
+
}),
|
|
10352
|
+
);
|
|
10267
10353
|
throw error;
|
|
10268
|
-
} finally {
|
|
10269
|
-
//a superseded load owns nothing, the newer one's busy state included
|
|
10270
|
-
if (!claim.stale) {
|
|
10271
|
-
this.removeAttribute('aria-busy');
|
|
10272
|
-
}
|
|
10273
10354
|
}
|
|
10274
10355
|
}
|
|
10275
10356
|
/** Hands the loader to the callback, for runtime reconfigurations. */
|
|
@@ -10306,6 +10387,7 @@ var fml = (function (exports) {
|
|
|
10306
10387
|
})
|
|
10307
10388
|
.render(),
|
|
10308
10389
|
);
|
|
10390
|
+
this.#empty.toggleAttribute('hidden', pageResponse.data.length !== 0);
|
|
10309
10391
|
//one move, one repaint: the page and the count are the same state
|
|
10310
10392
|
this.#paginator.update({ current: pageRequest.page, total: pages });
|
|
10311
10393
|
}
|
|
@@ -10559,6 +10641,19 @@ var fml = (function (exports) {
|
|
|
10559
10641
|
const sensitivityLabel = (sensitivity) => t(`filters.sensitivity.${sensitivity}`);
|
|
10560
10642
|
const booleanValueLabel = (token) => t(token === '' ? 'filters.boolean.any' : `filters.boolean.${token}`);
|
|
10561
10643
|
|
|
10644
|
+
/**
|
|
10645
|
+
* The operands are the words the reader chose, not the keys the wire carries.
|
|
10646
|
+
* @typedef {{ label: string|null, operator: string|null, operands: string[] }} FilterCriterion
|
|
10647
|
+
*/
|
|
10648
|
+
|
|
10649
|
+
const labelTextOf = (filter) => filter.querySelector(':scope > label')?.textContent.trim() || null;
|
|
10650
|
+
|
|
10651
|
+
/** @returns {FilterCriterion|null} */
|
|
10652
|
+
const asCriterion = (label, operator, operands) => {
|
|
10653
|
+
const shown = operands.filter((o) => o !== null && o !== undefined && `${o}` !== '');
|
|
10654
|
+
return shown.length === 0 ? null : { label, operator, operands: shown.map((o) => `${o}`) };
|
|
10655
|
+
};
|
|
10656
|
+
|
|
10562
10657
|
/**
|
|
10563
10658
|
* The shared shape of every operator-and-operands filter: an operator menu, one
|
|
10564
10659
|
* or two operands of the type the subclass declares, and a tuple that mirrors
|
|
@@ -10698,6 +10793,18 @@ var fml = (function (exports) {
|
|
|
10698
10793
|
_syncBetween() {
|
|
10699
10794
|
this._value2.toggleAttribute('hidden', this._operator.value !== 'BETWEEN');
|
|
10700
10795
|
}
|
|
10796
|
+
/**
|
|
10797
|
+
* The operands as shown rather than as serialized: a date filter describes
|
|
10798
|
+
* what is in its control, not the iso string it sends.
|
|
10799
|
+
* @returns {FilterCriterion|null}
|
|
10800
|
+
*/
|
|
10801
|
+
get criterion() {
|
|
10802
|
+
const operands =
|
|
10803
|
+
this._operator.value === 'BETWEEN'
|
|
10804
|
+
? [this._value1.value, this._value2.value]
|
|
10805
|
+
: [this._value1.value];
|
|
10806
|
+
return asCriterion(labelTextOf(this), this._operator.value, operands);
|
|
10807
|
+
}
|
|
10701
10808
|
get disabled() {
|
|
10702
10809
|
return super.disabled;
|
|
10703
10810
|
}
|
|
@@ -10933,6 +11040,13 @@ var fml = (function (exports) {
|
|
|
10933
11040
|
this._operator.value = this._operator.pinned ? this._operator.allowed[0] : v[0];
|
|
10934
11041
|
this._value.value = v[1] ?? '';
|
|
10935
11042
|
}
|
|
11043
|
+
/** @returns {FilterCriterion|null} */
|
|
11044
|
+
get criterion() {
|
|
11045
|
+
const token = this._value.value;
|
|
11046
|
+
return asCriterion(labelTextOf(this), this._operator.value, [
|
|
11047
|
+
token === '' ? '' : booleanValueLabel(token),
|
|
11048
|
+
]);
|
|
11049
|
+
}
|
|
10936
11050
|
get disabled() {
|
|
10937
11051
|
return super.disabled;
|
|
10938
11052
|
}
|
|
@@ -10945,6 +11059,37 @@ var fml = (function (exports) {
|
|
|
10945
11059
|
}
|
|
10946
11060
|
}
|
|
10947
11061
|
|
|
11062
|
+
/**
|
|
11063
|
+
* Set membership over a select's vocabulary, answering for both of data-jpa's
|
|
11064
|
+
* set annotations: InEnum and InList take the same bare array of values and no
|
|
11065
|
+
* operator, differing only in what the server converts them to.
|
|
11066
|
+
*/
|
|
11067
|
+
class InFilter extends Select {
|
|
11068
|
+
async upgrade() {
|
|
11069
|
+
//the snapshot is taken inside super.upgrade(), so an attribute this
|
|
11070
|
+
//element does not let an author turn off has to be written before it
|
|
11071
|
+
this.toggleAttribute('multiple', true);
|
|
11072
|
+
await super.upgrade();
|
|
11073
|
+
}
|
|
11074
|
+
get value() {
|
|
11075
|
+
const keys = super.value;
|
|
11076
|
+
//an empty set is no filter: the table drops a falsy value, where an
|
|
11077
|
+
//empty array would travel and match nothing
|
|
11078
|
+
return keys.length === 0 ? null : keys;
|
|
11079
|
+
}
|
|
11080
|
+
set value(v) {
|
|
11081
|
+
super.value = v ?? [];
|
|
11082
|
+
}
|
|
11083
|
+
/** @returns {FilterCriterion|null} */
|
|
11084
|
+
get criterion() {
|
|
11085
|
+
return asCriterion(
|
|
11086
|
+
labelTextOf(this),
|
|
11087
|
+
null,
|
|
11088
|
+
(super.entry ?? []).map((e) => e.label),
|
|
11089
|
+
);
|
|
11090
|
+
}
|
|
11091
|
+
}
|
|
11092
|
+
|
|
10948
11093
|
/**
|
|
10949
11094
|
* The async section machinery shared by ful-tabs, ful-wizard, ful-dialog and
|
|
10950
11095
|
* ful-drawer: every activation of a section fires the section:requested family
|
|
@@ -12108,6 +12253,7 @@ var fml = (function (exports) {
|
|
|
12108
12253
|
.defineElement('ful-filter-number', NumberFilter)
|
|
12109
12254
|
.defineElement('ful-filter-boolean', BooleanFilter)
|
|
12110
12255
|
.defineElement('ful-filter-text', TextFilter)
|
|
12256
|
+
.defineElement('ful-filter-in', InFilter)
|
|
12111
12257
|
.defineElement('ful-select', Select)
|
|
12112
12258
|
.defineElement('ful-dropdown', Dropdown)
|
|
12113
12259
|
.defineComponent('loaders:select', SelectLoader)
|
|
@@ -12140,6 +12286,7 @@ var fml = (function (exports) {
|
|
|
12140
12286
|
Field: Field,
|
|
12141
12287
|
Form: Form,
|
|
12142
12288
|
FormLoader: FormLoader,
|
|
12289
|
+
InFilter: InFilter,
|
|
12143
12290
|
Input: Input,
|
|
12144
12291
|
InputFile: InputFile,
|
|
12145
12292
|
InputInstant: InputInstant,
|
|
@@ -12208,6 +12355,7 @@ var fml = (function (exports) {
|
|
|
12208
12355
|
exports.HttpInterceptorChain = HttpInterceptorChain;
|
|
12209
12356
|
exports.HttpMultipartRequestCustomizer = HttpMultipartRequestCustomizer;
|
|
12210
12357
|
exports.HttpRequestBuilder = HttpRequestBuilder;
|
|
12358
|
+
exports.InFilter = InFilter;
|
|
12211
12359
|
exports.Input = Input;
|
|
12212
12360
|
exports.InputFile = InputFile;
|
|
12213
12361
|
exports.InputInstant = InputInstant;
|