@optionfactory/fml 9.0.0-rc10 → 9.0.0-rc12
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 +283 -13
- package/dist/fml.css +7 -6
- package/dist/fml.css.map +1 -1
- package/dist/fml.iife.js +205 -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 +7 -6
- package/dist/ful.css.map +1 -1
- package/dist/ful.d.mts +28 -1
- package/dist/ful.iife.js +204 -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 +204 -36
- package/dist/ful.mjs.map +1 -1
- package/dist/vscode.html-custom-data.json +134 -12
- package/dist/web-types.json +293 -14
- package/package.json +1 -1
package/dist/fml.iife.js
CHANGED
|
@@ -7636,6 +7636,29 @@ 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_DIGITS = {
|
|
7645
|
+
numeric: (t) => t.replace(/\D/g, ''),
|
|
7646
|
+
//one separator, the first: the rest are a slip while typing, not a value
|
|
7647
|
+
decimal: (t) => {
|
|
7648
|
+
const kept = t.replace(/[^\d.,]/g, '');
|
|
7649
|
+
const at = kept.search(/[.,]/);
|
|
7650
|
+
return at === -1 ? kept : kept.slice(0, at + 1) + kept.slice(at + 1).replace(/[.,]/g, '');
|
|
7651
|
+
},
|
|
7652
|
+
};
|
|
7653
|
+
|
|
7654
|
+
const numericFilter = (type, unsigned) => {
|
|
7655
|
+
const digits = NUMERIC_DIGITS[type];
|
|
7656
|
+
if (!digits) {
|
|
7657
|
+
return null;
|
|
7658
|
+
}
|
|
7659
|
+
return unsigned ? digits : (v) => signed(v, digits);
|
|
7660
|
+
};
|
|
7661
|
+
|
|
7639
7662
|
const warnedBoth = new WeakSet();
|
|
7640
7663
|
const filterOf = (el) => {
|
|
7641
7664
|
const keep = el.declared('keep');
|
|
@@ -7655,7 +7678,7 @@ var fml = (function (exports) {
|
|
|
7655
7678
|
const re = compiled('reject', reject);
|
|
7656
7679
|
return re && ((v) => v.replace(re, ''));
|
|
7657
7680
|
}
|
|
7658
|
-
return
|
|
7681
|
+
return numericFilter(el._type(), el.declared('unsigned'));
|
|
7659
7682
|
};
|
|
7660
7683
|
|
|
7661
7684
|
/** A labelled text input over any native type or textarea; the temporal inputs are its subclasses. */
|
|
@@ -7670,6 +7693,7 @@ var fml = (function (exports) {
|
|
|
7670
7693
|
'reject',
|
|
7671
7694
|
'uppercase:presence',
|
|
7672
7695
|
'trim:presence',
|
|
7696
|
+
'unsigned:presence',
|
|
7673
7697
|
'autocomplete',
|
|
7674
7698
|
];
|
|
7675
7699
|
static slots = true;
|
|
@@ -7691,9 +7715,17 @@ var fml = (function (exports) {
|
|
|
7691
7715
|
return this.declared('type') ?? (this.declared('v-type') === 'number' ? 'number' : 'text');
|
|
7692
7716
|
}
|
|
7693
7717
|
_build({ slots }) {
|
|
7694
|
-
const
|
|
7718
|
+
const declared = this._type();
|
|
7719
|
+
const mode = INPUT_MODES[declared];
|
|
7720
|
+
//a numeric widget is a text input: the type names the keyboard, not the
|
|
7721
|
+
//control, so the rendered markup stays valid html
|
|
7722
|
+
const type = mode ? 'text' : declared;
|
|
7695
7723
|
const fragment = this.template().withOverlay({ type, slots }).render();
|
|
7696
7724
|
this._input = fragment.querySelector('input,textarea');
|
|
7725
|
+
if (mode) {
|
|
7726
|
+
//before the passthrough, which stays the last word
|
|
7727
|
+
Attributes.set(this._input, 'inputmode', mode);
|
|
7728
|
+
}
|
|
7697
7729
|
|
|
7698
7730
|
//the browser reads autocomplete off the control it is classifying, so the
|
|
7699
7731
|
//field's own token, or the form's where it declares none, is put there.
|
|
@@ -7745,13 +7777,15 @@ var fml = (function (exports) {
|
|
|
7745
7777
|
if (trimmed === '') {
|
|
7746
7778
|
return null;
|
|
7747
7779
|
}
|
|
7780
|
+
//the wire carries a dot wherever the comma is what the keyboard shows
|
|
7781
|
+
const normalized = this._type() === 'decimal' ? trimmed.replaceAll(',', '.') : trimmed;
|
|
7748
7782
|
if (this.declared('v-type') === 'number') {
|
|
7749
7783
|
//typed values are an explicit opt in, as the select's k-type: blank
|
|
7750
7784
|
//stays null, and a value that does not decode is kept as it is
|
|
7751
|
-
const n = Number(
|
|
7752
|
-
return Number.isNaN(n) ?
|
|
7785
|
+
const n = Number(normalized);
|
|
7786
|
+
return Number.isNaN(n) ? normalized : n;
|
|
7753
7787
|
}
|
|
7754
|
-
return
|
|
7788
|
+
return normalized;
|
|
7755
7789
|
}
|
|
7756
7790
|
set value(value) {
|
|
7757
7791
|
this._input.value = value === '' || value === undefined ? null : value;
|
|
@@ -8743,10 +8777,27 @@ var fml = (function (exports) {
|
|
|
8743
8777
|
method: el.declared('method') ?? 'POST',
|
|
8744
8778
|
mode: el.declared('mode'),
|
|
8745
8779
|
prefetch: el.declared('preload'),
|
|
8746
|
-
revision: el
|
|
8780
|
+
revision: SelectLoader.#revisionFrom(el),
|
|
8747
8781
|
responseMapper: SelectLoader.#responseMapperFrom(el),
|
|
8748
8782
|
});
|
|
8749
8783
|
}
|
|
8784
|
+
static #revisionFrom(el) {
|
|
8785
|
+
const declared = el.declared('revision');
|
|
8786
|
+
if (declared !== '') {
|
|
8787
|
+
return declared;
|
|
8788
|
+
}
|
|
8789
|
+
const configured = el.component('revision');
|
|
8790
|
+
if (configured === undefined || configured === null) {
|
|
8791
|
+
//not caching while the markup says to cache is the quiet failure
|
|
8792
|
+
//this branch exists to make loud
|
|
8793
|
+
console.warn(
|
|
8794
|
+
"a valueless revision asks the registry for one, and no 'revision' component is defined: the vocabulary will not be cached",
|
|
8795
|
+
el,
|
|
8796
|
+
);
|
|
8797
|
+
return null;
|
|
8798
|
+
}
|
|
8799
|
+
return typeof configured === 'function' ? configured() : configured;
|
|
8800
|
+
}
|
|
8750
8801
|
static #responseMapperFrom(el) {
|
|
8751
8802
|
if (el.declared('k-expr') && el.declared('l-expr')) {
|
|
8752
8803
|
return (response) => {
|
|
@@ -8779,7 +8830,7 @@ var fml = (function (exports) {
|
|
|
8779
8830
|
static slots = true;
|
|
8780
8831
|
static template = `
|
|
8781
8832
|
<ful-spinner class="centered" role="status" hidden><span class="ful-sr-only">{{ #l10n:t('spinner.loading') }}</span></ful-spinner>
|
|
8782
|
-
<
|
|
8833
|
+
<ful-empty data-ref="empty" aria-live="polite" hidden>{{ #l10n:t('dropdown.empty') }}</ful-empty>
|
|
8783
8834
|
<menu tabindex="-1" role="listbox" hidden></menu>
|
|
8784
8835
|
`;
|
|
8785
8836
|
static templates = {
|
|
@@ -8801,7 +8852,7 @@ var fml = (function (exports) {
|
|
|
8801
8852
|
? this.template('options')
|
|
8802
8853
|
: Templates.fromFragment(slots.default);
|
|
8803
8854
|
this.#spinner = fragment.querySelector('ful-spinner');
|
|
8804
|
-
this.#empty = fragment.querySelector('
|
|
8855
|
+
this.#empty = fragment.querySelector('[data-ref=empty]');
|
|
8805
8856
|
this.#menu = fragment.querySelector('menu');
|
|
8806
8857
|
//the listbox is named so a combobox can point aria-controls and
|
|
8807
8858
|
//aria-activedescendant at it: a reference to an unnamed element resolves
|
|
@@ -9161,7 +9212,7 @@ var fml = (function (exports) {
|
|
|
9161
9212
|
return;
|
|
9162
9213
|
}
|
|
9163
9214
|
this.#abortdload();
|
|
9164
|
-
this.#close();
|
|
9215
|
+
this.#close(true);
|
|
9165
9216
|
});
|
|
9166
9217
|
this.#input.addEventListener('keydown', (e) => {
|
|
9167
9218
|
if (!this._interactive()) {
|
|
@@ -9194,7 +9245,6 @@ var fml = (function (exports) {
|
|
|
9194
9245
|
this.#editing = false;
|
|
9195
9246
|
this.#values.set(this.#coerceKey(e.detail.entry.key), e.detail.entry);
|
|
9196
9247
|
this.#changed();
|
|
9197
|
-
this.#syncBadges();
|
|
9198
9248
|
this.#input.focus();
|
|
9199
9249
|
this.#ddmenu.hide();
|
|
9200
9250
|
if (!this.#multiple) {
|
|
@@ -9251,7 +9301,6 @@ var fml = (function (exports) {
|
|
|
9251
9301
|
}
|
|
9252
9302
|
this.#values.delete(key);
|
|
9253
9303
|
this.#changed();
|
|
9254
|
-
this.#syncBadges();
|
|
9255
9304
|
}
|
|
9256
9305
|
#chipKeydown(e, badge) {
|
|
9257
9306
|
switch (e.code) {
|
|
@@ -9347,7 +9396,7 @@ var fml = (function (exports) {
|
|
|
9347
9396
|
}
|
|
9348
9397
|
case 'Tab': {
|
|
9349
9398
|
this.#abortdload();
|
|
9350
|
-
this.#close();
|
|
9399
|
+
this.#close(true);
|
|
9351
9400
|
break;
|
|
9352
9401
|
}
|
|
9353
9402
|
}
|
|
@@ -9363,12 +9412,25 @@ var fml = (function (exports) {
|
|
|
9363
9412
|
}
|
|
9364
9413
|
return;
|
|
9365
9414
|
}
|
|
9366
|
-
this.#
|
|
9367
|
-
this.#ddmenu.moveOrShow(forward, () => this.#loader.load(this.#input.value), [...this.#values.keys()]);
|
|
9415
|
+
this.#ddmenu.moveOrShow(forward, () => this.#loader.load(this.#query()), [...this.#values.keys()]);
|
|
9368
9416
|
}
|
|
9369
|
-
|
|
9417
|
+
/**
|
|
9418
|
+
* @param commit whether the user is leaving the field, which only a blur or
|
|
9419
|
+
* a Tab is: Escape cancels, and closing the list or a claim landing leaves
|
|
9420
|
+
* the edit in progress
|
|
9421
|
+
*/
|
|
9422
|
+
#close(commit = false) {
|
|
9370
9423
|
this.#ddmenu.hide();
|
|
9424
|
+
//emptying the box and leaving is a clear: redisplaying the label would
|
|
9425
|
+
//discard the edit without a word. A multiple select keeps its box empty
|
|
9426
|
+
//by design, so only a single one can mean it
|
|
9427
|
+
const cleared =
|
|
9428
|
+
commit && this.#editing && !this.#multiple && this.#input.value === '' && this.#values.size !== 0;
|
|
9371
9429
|
this.#editing = false;
|
|
9430
|
+
if (cleared) {
|
|
9431
|
+
this.#values.clear();
|
|
9432
|
+
this.#changed();
|
|
9433
|
+
}
|
|
9372
9434
|
this.#display();
|
|
9373
9435
|
}
|
|
9374
9436
|
/**
|
|
@@ -9377,14 +9439,15 @@ var fml = (function (exports) {
|
|
|
9377
9439
|
* highlighted.
|
|
9378
9440
|
*/
|
|
9379
9441
|
#open() {
|
|
9380
|
-
this.#
|
|
9381
|
-
return this.#ddmenu.show(() => this.#loader.load(this.#input.value), [...this.#values.keys()]);
|
|
9442
|
+
return this.#ddmenu.show(() => this.#loader.load(this.#query()), [...this.#values.keys()]);
|
|
9382
9443
|
}
|
|
9383
|
-
|
|
9384
|
-
|
|
9385
|
-
|
|
9386
|
-
|
|
9387
|
-
|
|
9444
|
+
/**
|
|
9445
|
+
* Browsing is the whole vocabulary, not the label already chosen, and the
|
|
9446
|
+
* label stays on screen while it happens: a select showing nothing reads as
|
|
9447
|
+
* an empty one.
|
|
9448
|
+
*/
|
|
9449
|
+
#query() {
|
|
9450
|
+
return this.#editing ? this.#input.value : '';
|
|
9388
9451
|
}
|
|
9389
9452
|
#display() {
|
|
9390
9453
|
const entry = this.#values.values().next().value;
|
|
@@ -9395,6 +9458,9 @@ var fml = (function (exports) {
|
|
|
9395
9458
|
return [...this.#values.values()];
|
|
9396
9459
|
}
|
|
9397
9460
|
#changed() {
|
|
9461
|
+
//settled before the event: a listener reading the control during it has to
|
|
9462
|
+
//see the selection that caused it
|
|
9463
|
+
this.#syncBadges();
|
|
9398
9464
|
//the detail carries the keys the value property answers with, as every
|
|
9399
9465
|
//other field's does, and the labeled selection beside them
|
|
9400
9466
|
this._notifyChange({ entry: this.entry });
|
|
@@ -10041,6 +10107,7 @@ var fml = (function (exports) {
|
|
|
10041
10107
|
static slots = true;
|
|
10042
10108
|
static config = {
|
|
10043
10109
|
searchIcon: 'search',
|
|
10110
|
+
emptyIcon: 'inbox',
|
|
10044
10111
|
};
|
|
10045
10112
|
static template = `
|
|
10046
10113
|
<ful-form data-tpl-if="slots.filters">
|
|
@@ -10054,10 +10121,21 @@ var fml = (function (exports) {
|
|
|
10054
10121
|
<tbody data-ref="initial">
|
|
10055
10122
|
<tr>
|
|
10056
10123
|
<td data-tpl-colspan="schema.length">
|
|
10057
|
-
<
|
|
10058
|
-
<
|
|
10124
|
+
<ful-empty>
|
|
10125
|
+
<ful-icon data-tpl-if="config.searchIcon" data-tpl-name="config.searchIcon" aria-hidden="true"></ful-icon>
|
|
10059
10126
|
{{ #l10n:t('table.initial') }}
|
|
10060
|
-
</
|
|
10127
|
+
</ful-empty>
|
|
10128
|
+
</td>
|
|
10129
|
+
</tr>
|
|
10130
|
+
</tbody>
|
|
10131
|
+
<tbody data-ref="empty" hidden>
|
|
10132
|
+
<tr>
|
|
10133
|
+
<td data-tpl-colspan="schema.length">
|
|
10134
|
+
<ful-empty data-tpl-if="slots.empty">{{{{ slots.empty }}}}</ful-empty>
|
|
10135
|
+
<ful-empty data-tpl-if="!slots.empty">
|
|
10136
|
+
<ful-icon data-tpl-if="config.emptyIcon" data-tpl-name="config.emptyIcon" aria-hidden="true"></ful-icon>
|
|
10137
|
+
{{ #l10n:t('table.no-data') }}
|
|
10138
|
+
</ful-empty>
|
|
10061
10139
|
</td>
|
|
10062
10140
|
</tr>
|
|
10063
10141
|
</tbody>
|
|
@@ -10087,11 +10165,6 @@ var fml = (function (exports) {
|
|
|
10087
10165
|
`;
|
|
10088
10166
|
static templates = {
|
|
10089
10167
|
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
10168
|
{{{{ schema.rowsTemplate.withOverlay({'rows': pageResponse.data}).render() }}}}
|
|
10096
10169
|
`,
|
|
10097
10170
|
};
|
|
@@ -10100,6 +10173,7 @@ var fml = (function (exports) {
|
|
|
10100
10173
|
#body;
|
|
10101
10174
|
#loading;
|
|
10102
10175
|
#noAutoload;
|
|
10176
|
+
#empty;
|
|
10103
10177
|
#feedback;
|
|
10104
10178
|
#paginator;
|
|
10105
10179
|
#sorters;
|
|
@@ -10150,6 +10224,7 @@ var fml = (function (exports) {
|
|
|
10150
10224
|
this.#body = table.querySelector(':scope > tbody');
|
|
10151
10225
|
this.#loading = table.querySelector(':scope > tbody[data-ref=loading]');
|
|
10152
10226
|
this.#noAutoload = table.querySelector(':scope > tbody[data-ref=initial]');
|
|
10227
|
+
this.#empty = table.querySelector(':scope > tbody[data-ref=empty]');
|
|
10153
10228
|
this.#feedback = table.querySelector(':scope > tbody[data-ref=feedback]');
|
|
10154
10229
|
this.#paginator = Nodes.queryChildren(fragment, 'ful-pagination');
|
|
10155
10230
|
this.replaceChildren(fragment);
|
|
@@ -10240,6 +10315,7 @@ var fml = (function (exports) {
|
|
|
10240
10315
|
this.#loading.toggleAttribute('hidden', this.#body.childElementCount > 0);
|
|
10241
10316
|
this.#feedback.setAttribute('hidden', '');
|
|
10242
10317
|
this.#noAutoload.setAttribute('hidden', '');
|
|
10318
|
+
this.#empty.setAttribute('hidden', '');
|
|
10243
10319
|
this.setAttribute('aria-busy', 'true');
|
|
10244
10320
|
try {
|
|
10245
10321
|
const pageResponse = await this.#loader.load(pageRequest, sortRequest, filterRequest);
|
|
@@ -10248,6 +10324,16 @@ var fml = (function (exports) {
|
|
|
10248
10324
|
}
|
|
10249
10325
|
this.#latestRequest = { pageRequest, sortRequest, filterRequest };
|
|
10250
10326
|
this.#update(pageRequest, sortRequest, filterRequest, pageResponse);
|
|
10327
|
+
//settled before the event: a listener counting what loaded has to
|
|
10328
|
+
//see the table as it now is
|
|
10329
|
+
this.removeAttribute('aria-busy');
|
|
10330
|
+
this.dispatchEvent(
|
|
10331
|
+
new CustomEvent('load:success', {
|
|
10332
|
+
bubbles: true,
|
|
10333
|
+
cancelable: false,
|
|
10334
|
+
detail: { pageRequest, sortRequest, filterRequest, response: pageResponse },
|
|
10335
|
+
}),
|
|
10336
|
+
);
|
|
10251
10337
|
} catch (/** @type any */ error) {
|
|
10252
10338
|
if (claim.stale) {
|
|
10253
10339
|
//the newer load owns the table and its outcome: a superseded
|
|
@@ -10264,12 +10350,15 @@ var fml = (function (exports) {
|
|
|
10264
10350
|
error,
|
|
10265
10351
|
`${error}`,
|
|
10266
10352
|
);
|
|
10353
|
+
this.removeAttribute('aria-busy');
|
|
10354
|
+
this.dispatchEvent(
|
|
10355
|
+
new CustomEvent('load:failure', {
|
|
10356
|
+
bubbles: true,
|
|
10357
|
+
cancelable: false,
|
|
10358
|
+
detail: { pageRequest, sortRequest, filterRequest, exception: error },
|
|
10359
|
+
}),
|
|
10360
|
+
);
|
|
10267
10361
|
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
10362
|
}
|
|
10274
10363
|
}
|
|
10275
10364
|
/** Hands the loader to the callback, for runtime reconfigurations. */
|
|
@@ -10306,6 +10395,7 @@ var fml = (function (exports) {
|
|
|
10306
10395
|
})
|
|
10307
10396
|
.render(),
|
|
10308
10397
|
);
|
|
10398
|
+
this.#empty.toggleAttribute('hidden', pageResponse.data.length !== 0);
|
|
10309
10399
|
//one move, one repaint: the page and the count are the same state
|
|
10310
10400
|
this.#paginator.update({ current: pageRequest.page, total: pages });
|
|
10311
10401
|
}
|
|
@@ -10559,6 +10649,19 @@ var fml = (function (exports) {
|
|
|
10559
10649
|
const sensitivityLabel = (sensitivity) => t(`filters.sensitivity.${sensitivity}`);
|
|
10560
10650
|
const booleanValueLabel = (token) => t(token === '' ? 'filters.boolean.any' : `filters.boolean.${token}`);
|
|
10561
10651
|
|
|
10652
|
+
/**
|
|
10653
|
+
* The operands are the words the reader chose, not the keys the wire carries.
|
|
10654
|
+
* @typedef {{ label: string|null, operator: string|null, operands: string[] }} FilterCriterion
|
|
10655
|
+
*/
|
|
10656
|
+
|
|
10657
|
+
const labelTextOf = (filter) => filter.querySelector(':scope > label')?.textContent.trim() || null;
|
|
10658
|
+
|
|
10659
|
+
/** @returns {FilterCriterion|null} */
|
|
10660
|
+
const asCriterion = (label, operator, operands) => {
|
|
10661
|
+
const shown = operands.filter((o) => o !== null && o !== undefined && `${o}` !== '');
|
|
10662
|
+
return shown.length === 0 ? null : { label, operator, operands: shown.map((o) => `${o}`) };
|
|
10663
|
+
};
|
|
10664
|
+
|
|
10562
10665
|
/**
|
|
10563
10666
|
* The shared shape of every operator-and-operands filter: an operator menu, one
|
|
10564
10667
|
* or two operands of the type the subclass declares, and a tuple that mirrors
|
|
@@ -10698,6 +10801,18 @@ var fml = (function (exports) {
|
|
|
10698
10801
|
_syncBetween() {
|
|
10699
10802
|
this._value2.toggleAttribute('hidden', this._operator.value !== 'BETWEEN');
|
|
10700
10803
|
}
|
|
10804
|
+
/**
|
|
10805
|
+
* The operands as shown rather than as serialized: a date filter describes
|
|
10806
|
+
* what is in its control, not the iso string it sends.
|
|
10807
|
+
* @returns {FilterCriterion|null}
|
|
10808
|
+
*/
|
|
10809
|
+
get criterion() {
|
|
10810
|
+
const operands =
|
|
10811
|
+
this._operator.value === 'BETWEEN'
|
|
10812
|
+
? [this._value1.value, this._value2.value]
|
|
10813
|
+
: [this._value1.value];
|
|
10814
|
+
return asCriterion(labelTextOf(this), this._operator.value, operands);
|
|
10815
|
+
}
|
|
10701
10816
|
get disabled() {
|
|
10702
10817
|
return super.disabled;
|
|
10703
10818
|
}
|
|
@@ -10933,6 +11048,13 @@ var fml = (function (exports) {
|
|
|
10933
11048
|
this._operator.value = this._operator.pinned ? this._operator.allowed[0] : v[0];
|
|
10934
11049
|
this._value.value = v[1] ?? '';
|
|
10935
11050
|
}
|
|
11051
|
+
/** @returns {FilterCriterion|null} */
|
|
11052
|
+
get criterion() {
|
|
11053
|
+
const token = this._value.value;
|
|
11054
|
+
return asCriterion(labelTextOf(this), this._operator.value, [
|
|
11055
|
+
token === '' ? '' : booleanValueLabel(token),
|
|
11056
|
+
]);
|
|
11057
|
+
}
|
|
10936
11058
|
get disabled() {
|
|
10937
11059
|
return super.disabled;
|
|
10938
11060
|
}
|
|
@@ -10945,6 +11067,51 @@ var fml = (function (exports) {
|
|
|
10945
11067
|
}
|
|
10946
11068
|
}
|
|
10947
11069
|
|
|
11070
|
+
/**
|
|
11071
|
+
* Set membership over a select's vocabulary, answering for both of data-jpa's
|
|
11072
|
+
* set annotations: InEnum and InList take the same bare array of values and no
|
|
11073
|
+
* operator, differing only in what the server converts them to.
|
|
11074
|
+
*/
|
|
11075
|
+
class InFilter extends Select {
|
|
11076
|
+
static attributes = ['operator'];
|
|
11077
|
+
/** the selection as the array the wire takes, whether one key was chosen or many */
|
|
11078
|
+
#keys() {
|
|
11079
|
+
const chosen = super.value;
|
|
11080
|
+
if (this.multiple) {
|
|
11081
|
+
return chosen;
|
|
11082
|
+
}
|
|
11083
|
+
return chosen === null || chosen === undefined ? [] : [chosen];
|
|
11084
|
+
}
|
|
11085
|
+
get value() {
|
|
11086
|
+
const keys = this.#keys();
|
|
11087
|
+
//an empty set is no filter: the table drops a falsy value, where an
|
|
11088
|
+
//empty array would travel and match nothing
|
|
11089
|
+
if (keys.length === 0) {
|
|
11090
|
+
return null;
|
|
11091
|
+
}
|
|
11092
|
+
const operator = this.declared('operator');
|
|
11093
|
+
return operator ? [operator, ...keys] : keys;
|
|
11094
|
+
}
|
|
11095
|
+
set value(v) {
|
|
11096
|
+
const operator = this.declared('operator');
|
|
11097
|
+
let keys = v === null || v === undefined ? [] : Array.isArray(v) ? v : [v];
|
|
11098
|
+
//what the getter answers has to be assignable back, and it carries the
|
|
11099
|
+
//operator in front of the keys
|
|
11100
|
+
if (operator && keys[0] === operator) {
|
|
11101
|
+
keys = keys.slice(1);
|
|
11102
|
+
}
|
|
11103
|
+
super.value = this.multiple ? keys : (keys[0] ?? null);
|
|
11104
|
+
}
|
|
11105
|
+
/** @returns {FilterCriterion|null} */
|
|
11106
|
+
get criterion() {
|
|
11107
|
+
return asCriterion(
|
|
11108
|
+
labelTextOf(this),
|
|
11109
|
+
this.declared('operator'),
|
|
11110
|
+
[super.entry].flat().filter((e) => e).map((e) => e.label),
|
|
11111
|
+
);
|
|
11112
|
+
}
|
|
11113
|
+
}
|
|
11114
|
+
|
|
10948
11115
|
/**
|
|
10949
11116
|
* The async section machinery shared by ful-tabs, ful-wizard, ful-dialog and
|
|
10950
11117
|
* ful-drawer: every activation of a section fires the section:requested family
|
|
@@ -12108,6 +12275,7 @@ var fml = (function (exports) {
|
|
|
12108
12275
|
.defineElement('ful-filter-number', NumberFilter)
|
|
12109
12276
|
.defineElement('ful-filter-boolean', BooleanFilter)
|
|
12110
12277
|
.defineElement('ful-filter-text', TextFilter)
|
|
12278
|
+
.defineElement('ful-filter-in', InFilter)
|
|
12111
12279
|
.defineElement('ful-select', Select)
|
|
12112
12280
|
.defineElement('ful-dropdown', Dropdown)
|
|
12113
12281
|
.defineComponent('loaders:select', SelectLoader)
|
|
@@ -12140,6 +12308,7 @@ var fml = (function (exports) {
|
|
|
12140
12308
|
Field: Field,
|
|
12141
12309
|
Form: Form,
|
|
12142
12310
|
FormLoader: FormLoader,
|
|
12311
|
+
InFilter: InFilter,
|
|
12143
12312
|
Input: Input,
|
|
12144
12313
|
InputFile: InputFile,
|
|
12145
12314
|
InputInstant: InputInstant,
|
|
@@ -12208,6 +12377,7 @@ var fml = (function (exports) {
|
|
|
12208
12377
|
exports.HttpInterceptorChain = HttpInterceptorChain;
|
|
12209
12378
|
exports.HttpMultipartRequestCustomizer = HttpMultipartRequestCustomizer;
|
|
12210
12379
|
exports.HttpRequestBuilder = HttpRequestBuilder;
|
|
12380
|
+
exports.InFilter = InFilter;
|
|
12211
12381
|
exports.Input = Input;
|
|
12212
12382
|
exports.InputFile = InputFile;
|
|
12213
12383
|
exports.InputInstant = InputInstant;
|