pict-section-picker 1.1.0 → 1.3.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/README.md +56 -0
- package/package.json +1 -1
- package/source/form/Pict-Section-Picker-FormInput.js +11 -0
- package/source/providers/Pict-Provider-Picker.js +153 -6
- package/source/views/PictView-Picker.js +47 -15
- package/types/form/Pict-Section-Picker-FormInput.d.ts +8 -0
- package/types/form/Pict-Section-Picker-FormInput.d.ts.map +1 -1
- package/types/providers/Pict-Provider-Picker.d.ts +64 -0
- package/types/providers/Pict-Provider-Picker.d.ts.map +1 -1
- package/types/views/PictView-Picker.d.ts +14 -2
- package/types/views/PictView-Picker.d.ts.map +1 -1
package/README.md
CHANGED
|
@@ -117,6 +117,62 @@ Entity-source configuration:
|
|
|
117
117
|
|
|
118
118
|
The lower-level builders are also exposed: `createEntityDataProvider(cfg)` and `createEntityResolveValue(cfg)` return the raw functions if you want to wire them yourself.
|
|
119
119
|
|
|
120
|
+
## Joined display (parent-entity context)
|
|
121
|
+
|
|
122
|
+
Sometimes a searched entity is ambiguous on its own — a `LineItem` only makes sense next to its `Project`, a `Review` next to its `Book`. Set `JoinEntity` and the picker renders a **compound** label by joining each searched row to a parent entity through a foreign key the row carries:
|
|
123
|
+
|
|
124
|
+
```javascript
|
|
125
|
+
tmpPicker.createEntityPicker('ReviewPicker',
|
|
126
|
+
{
|
|
127
|
+
Entity: 'Review',
|
|
128
|
+
SearchFields: [ 'Summary' ],
|
|
129
|
+
JoinEntity: 'Book', // the parent entity to join
|
|
130
|
+
JoinField: 'IDBook', // the FK on the Review row -> Book
|
|
131
|
+
JoinEntityDisplayField: 'Title', // the Book field to show
|
|
132
|
+
DestinationAddress: '#ReviewPicker',
|
|
133
|
+
ValueAddress: 'AppData.Form.IDReview',
|
|
134
|
+
});
|
|
135
|
+
// options render as "Neuromancer - Loved it"; the Value is still IDReview.
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Meadow can't join in a single read, so this is **fetch-then-merge**: after each search page the picker collects the rows' unique FK ids and issues **one** `FBL~ID{JoinEntity}~INN~<ids>` request, then stitches the joined display onto every row (also exposed as `Record.JoinName` / `Record.JoinRecord` for `MapRecord` / templates). The same join resolves a pre-bound value's label on first render.
|
|
139
|
+
|
|
140
|
+
| Option | Default | Purpose |
|
|
141
|
+
|---|---|---|
|
|
142
|
+
| `JoinEntity` | — | Parent entity to join for the compound display. Setting it enables the feature. |
|
|
143
|
+
| `JoinField` | `ID<JoinEntity>` | The FK column **on the searched row** pointing at `JoinEntity`. |
|
|
144
|
+
| `JoinEntityValueField` | `ID<JoinEntity>` | The PK column on `JoinEntity` to match (the `INN` column). |
|
|
145
|
+
| `JoinEntityDisplayField` | `'Name'` | The `JoinEntity` field shown in the compound label. |
|
|
146
|
+
| `JoinEntityFirst` | `true` | `true` → `Parent - Row`; `false` → `Row - Parent`. |
|
|
147
|
+
| `JoinSeparator` | `' - '` | Separator between the two parts. |
|
|
148
|
+
|
|
149
|
+
The same options ride through the form-input adapter (`PictForm.JoinEntity`, …) and the pict-section-recordset entity filters (set `JoinEntity` on the clause) — so an entity filter can show parent context for its options with no host code, layered on top of either the 1:1 (direct-FK / `InternalJoin`) or 1:many (junction / `ExternalJoin`) filter relationship.
|
|
150
|
+
|
|
151
|
+
## Tag badge (EntityTag)
|
|
152
|
+
|
|
153
|
+
Show a small code/number badge next to each option — the select2 `EntitySelector` "tag" parity. For entity pickers, `EntityTag` names the record field to badge; the picker renders it as a pill beside the label:
|
|
154
|
+
|
|
155
|
+
```javascript
|
|
156
|
+
tmpPicker.createEntityPicker('PayItemPicker',
|
|
157
|
+
{
|
|
158
|
+
Entity: 'PayItem',
|
|
159
|
+
SearchFields: [ 'Name' ],
|
|
160
|
+
EntityTag: 'ItemCode', // each option shows its ItemCode as a badge
|
|
161
|
+
DestinationAddress: '#PayItemPicker',
|
|
162
|
+
ValueAddress: 'AppData.Form.IDPayItem',
|
|
163
|
+
});
|
|
164
|
+
// options render as badge + label, e.g. [201-1] Excavation
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Static options can carry a `Tag` directly (`{ Value, Text, Tag }`). The badge rides on the dropdown options, the selected single value, and multi-select chips alike. It composes with JoinEntity — the join folds into the label, the tag stays a separate pill.
|
|
168
|
+
|
|
169
|
+
| Option | Default | Purpose |
|
|
170
|
+
|---|---|---|
|
|
171
|
+
| `EntityTag` | — | (entity pickers) record field whose value becomes each option's `Tag` badge. |
|
|
172
|
+
| `TagLast` | `false` | `false` → badge before the label; `true` → after. |
|
|
173
|
+
|
|
174
|
+
Through the form-input adapter + the recordset entity filters these are `PictForm.EntityTag` / `PictForm.EntityTagLast`.
|
|
175
|
+
|
|
120
176
|
## Categories
|
|
121
177
|
|
|
122
178
|
Give option rows an optional `Group` field and the list renders headered sections (preserving order; rows without a `Group` fall into a leading unlabeled section):
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pict-section-picker",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Pict-native themeable searchable select / combobox — single & multi select, server pagination, categorized groups and creatable entries, driven by a host-agnostic async DataProvider (with a built-in Meadow EntityProvider adapter). A jQuery/select2-free replacement.",
|
|
5
5
|
"main": "source/Pict-Section-Picker.js",
|
|
6
6
|
"types": "types/Pict-Section-Picker.d.ts",
|
|
@@ -117,6 +117,17 @@ class PictInputTypePicker extends libPictInputExtension
|
|
|
117
117
|
TextField: tmpPF.TextField,
|
|
118
118
|
PageSize: tmpPF.PageSize || 20,
|
|
119
119
|
Options: tmpPF.Options || [],
|
|
120
|
+
// JoinEntity compound display (1:1 / 1:many parent-entity context) — passed straight through
|
|
121
|
+
// to the picker's entity adapter, which fetch-then-merges the join. No-op when JoinEntity unset.
|
|
122
|
+
JoinEntity: tmpPF.JoinEntity,
|
|
123
|
+
JoinField: tmpPF.JoinField,
|
|
124
|
+
JoinEntityValueField: tmpPF.JoinEntityValueField,
|
|
125
|
+
JoinEntityDisplayField: tmpPF.JoinEntityDisplayField,
|
|
126
|
+
JoinEntityFirst: tmpPF.JoinEntityFirst,
|
|
127
|
+
JoinSeparator: tmpPF.JoinSeparator,
|
|
128
|
+
// EntityTag badge: the record field whose value becomes a Tag pill, ordered by EntityTagLast.
|
|
129
|
+
EntityTag: tmpPF.EntityTag,
|
|
130
|
+
TagLast: tmpPF.EntityTagLast,
|
|
120
131
|
// Per-search contextual scope — the generic hook the host fills.
|
|
121
132
|
BaseFilter: () => this.getContextualSearchFilters(pInput),
|
|
122
133
|
OnChange: fOnChange,
|
|
@@ -31,6 +31,16 @@ const _PickerCSS = /*css*/`
|
|
|
31
31
|
.pps-chip-x { flex: 0 0 auto; display: inline-flex; align-items: center; cursor: pointer; font-size: 0.78rem; border-radius: 4px; padding: 0.1rem; opacity: 0.7; }
|
|
32
32
|
.pps-chip-x:hover { opacity: 1; background: color-mix(in srgb, var(--theme-color-brand-primary, #156dd1) 22%, transparent); }
|
|
33
33
|
|
|
34
|
+
/* EntityTag badge — a small code/number pill shown next to an option / chip / selected value (the
|
|
35
|
+
select2 EntitySelector "tag" parity). Ordering (before/after the label) is driven by the TagLast
|
|
36
|
+
option in the view's render state. */
|
|
37
|
+
.pps-tag { flex: 0 0 auto; display: inline-flex; align-items: center; font-size: 0.74rem; font-weight: 600; line-height: 1.25;
|
|
38
|
+
padding: 0.05rem 0.4rem; border-radius: 5px; white-space: nowrap;
|
|
39
|
+
background: var(--theme-color-background-tertiary, #eceef2); color: var(--theme-color-text-secondary, #45596b); }
|
|
40
|
+
.pps-valuebox { display: flex; align-items: center; gap: 0.4rem; min-width: 0; }
|
|
41
|
+
.pps-valuebox .pps-value { min-width: 0; }
|
|
42
|
+
.pps-option-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
43
|
+
|
|
34
44
|
/* Transparent full-viewport backdrop: closes on outside click (no document listener). Only present
|
|
35
45
|
while OPEN — otherwise a fixed full-viewport layer would swallow every click on the page. When open,
|
|
36
46
|
the control is raised above it so its chips/× stay clickable; the dropdown sits above both. */
|
|
@@ -174,6 +184,20 @@ class PictProviderPicker extends libPictProvider
|
|
|
174
184
|
* evaluated on every search — the generic hook for host-injected CONTEXTUAL scoping (project,
|
|
175
185
|
* tenant, spec-year, …). The module stays agnostic; the host supplies the closure.
|
|
176
186
|
* - MapRecord {function} - optional `(record) => {Value, Text}` mapper (overrides Value/TextField).
|
|
187
|
+
* - JoinEntity {string} - optional second entity to JOIN for a compound display (e.g. a `LineItem`
|
|
188
|
+
* shown with its `Project`). Each searched row must carry the FK (`JoinField`). Because Meadow
|
|
189
|
+
* can't join in one read, this is fetch-then-merge: after the primary page resolves, the unique
|
|
190
|
+
* FK ids drive ONE `FBL~ID{JoinEntity}~INN~<ids>` request, and the joined display field is
|
|
191
|
+
* stitched onto each row (as `Record.JoinName` / `Record.JoinRecord`) + composed into the Text.
|
|
192
|
+
* - JoinField {string} - the FK column ON THE SEARCHED ROW pointing at JoinEntity (default `ID{JoinEntity}`).
|
|
193
|
+
* - JoinEntityValueField {string} - the PK column on JoinEntity to match (default `ID{JoinEntity}`).
|
|
194
|
+
* - JoinEntityDisplayField {string} - the JoinEntity field to display (default `Name`).
|
|
195
|
+
* - JoinEntityFirst {boolean} - put the joined value first in the compound (default `true`):
|
|
196
|
+
* `JoinName - baseText`; when `false`, `baseText - JoinName`.
|
|
197
|
+
* - JoinSeparator {string} - the compound separator (default `' - '`).
|
|
198
|
+
* - EntityTag {string} - optional record field whose value becomes a `Tag` badge on each option
|
|
199
|
+
* (e.g. a `LineItem`'s `ItemNumber`). The picker view renders it as a styled badge alongside the
|
|
200
|
+
* label (ordering via the picker's `TagLast` option). Composes with JoinEntity (tag is outermost).
|
|
177
201
|
* @return {(pSearchTerm: string, pPage: number) => Promise<{results: Array<any>, hasMore: boolean}>}
|
|
178
202
|
*/
|
|
179
203
|
createEntityDataProvider(pConfig)
|
|
@@ -186,6 +210,8 @@ class PictProviderPicker extends libPictProvider
|
|
|
186
210
|
const tmpSort = pConfig.Sort || false;
|
|
187
211
|
const tmpBaseFilterConfig = pConfig.BaseFilter || '';
|
|
188
212
|
const tmpMapRecord = (typeof pConfig.MapRecord === 'function') ? pConfig.MapRecord : false;
|
|
213
|
+
const tmpJoinConfig = this._resolveJoinConfig(pConfig);
|
|
214
|
+
const tmpEntityTagField = pConfig.EntityTag || false;
|
|
189
215
|
|
|
190
216
|
return (pSearchTerm, pPage) => new Promise((resolve, reject) =>
|
|
191
217
|
{
|
|
@@ -217,11 +243,117 @@ class PictProviderPicker extends libPictProvider
|
|
|
217
243
|
{
|
|
218
244
|
if (pError) { return reject(pError); }
|
|
219
245
|
const tmpList = Array.isArray(pRecords) ? pRecords : [];
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
246
|
+
// JoinEntity (when configured): one INN fetch for the joined rows, stitched onto each
|
|
247
|
+
// searched row, before mapping — so the option Text can show the compound display.
|
|
248
|
+
this._decorateRecordsWithJoin(tmpList, tmpJoinConfig).then((pDecorated) =>
|
|
249
|
+
{
|
|
250
|
+
const tmpResults = pDecorated.map((pRecord) => tmpMapRecord
|
|
251
|
+
? tmpMapRecord(pRecord)
|
|
252
|
+
: this._composeOption(pRecord, tmpValueField, tmpTextField, tmpJoinConfig, tmpEntityTagField));
|
|
253
|
+
// hasMore: a full page came back, so there is (probably) another. Avoids a Count round-trip.
|
|
254
|
+
return resolve({ results: tmpResults, hasMore: (tmpList.length >= tmpPageSize) });
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Resolve the JoinEntity options off an entity-source config into a normalized internal shape, or
|
|
262
|
+
* `false` when no JoinEntity is configured. Centralizes the defaults so the DataProvider and the
|
|
263
|
+
* ResolveValue builders agree.
|
|
264
|
+
*
|
|
265
|
+
* @param {Record<string, any>} pConfig
|
|
266
|
+
* @return {false | {Entity:string, FKColumn:string, PKColumn:string, DisplayField:string, First:boolean, Separator:string}}
|
|
267
|
+
*/
|
|
268
|
+
_resolveJoinConfig(pConfig)
|
|
269
|
+
{
|
|
270
|
+
if (!pConfig || !pConfig.JoinEntity) { return false; }
|
|
271
|
+
return {
|
|
272
|
+
Entity: pConfig.JoinEntity,
|
|
273
|
+
// The FK on the SEARCHED row, and the PK it points at on the join entity (the INN column).
|
|
274
|
+
FKColumn: pConfig.JoinField || `ID${pConfig.JoinEntity}`,
|
|
275
|
+
PKColumn: pConfig.JoinEntityValueField || `ID${pConfig.JoinEntity}`,
|
|
276
|
+
DisplayField: pConfig.JoinEntityDisplayField || 'Name',
|
|
277
|
+
// Default join-first (mirrors the documented select2 EntitySelector default).
|
|
278
|
+
First: (pConfig.JoinEntityFirst !== false),
|
|
279
|
+
Separator: (typeof pConfig.JoinSeparator === 'string') ? pConfig.JoinSeparator : ' - ',
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Compose a compound display from a base text + a joined value, honoring ordering + separator.
|
|
285
|
+
* Falls back to just the base text when there is no joined value.
|
|
286
|
+
*
|
|
287
|
+
* @param {any} pBaseText @param {any} pJoinText @param {boolean} pFirst @param {string} pSeparator
|
|
288
|
+
* @return {any}
|
|
289
|
+
*/
|
|
290
|
+
_composeJoinedText(pBaseText, pJoinText, pFirst, pSeparator)
|
|
291
|
+
{
|
|
292
|
+
if (pJoinText === undefined || pJoinText === null || pJoinText === '') { return pBaseText; }
|
|
293
|
+
const tmpBase = (pBaseText === undefined || pBaseText === null) ? '' : pBaseText;
|
|
294
|
+
return pFirst ? `${pJoinText}${pSeparator}${tmpBase}` : `${tmpBase}${pSeparator}${pJoinText}`;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Build the picker option `{ Value, Text, Record[, Tag] }` from a (possibly join-decorated) record:
|
|
299
|
+
* the Text honors any JoinEntity compound, and a Tag badge is added from `pTagField` when set. Shared
|
|
300
|
+
* by the DataProvider (per page row) and the ResolveValue (pre-bound value) so they stay consistent.
|
|
301
|
+
*
|
|
302
|
+
* @param {any} pRecord @param {string} pValueField @param {string} pTextField
|
|
303
|
+
* @param {false | Record<string, any>} pJoinConfig @param {string|false} pTagField
|
|
304
|
+
* @return {{Value:any, Text:any, Record:any, Tag?:any}}
|
|
305
|
+
*/
|
|
306
|
+
_composeOption(pRecord, pValueField, pTextField, pJoinConfig, pTagField)
|
|
307
|
+
{
|
|
308
|
+
const tmpText = pJoinConfig
|
|
309
|
+
? this._composeJoinedText(pRecord[pTextField], pRecord.JoinName, pJoinConfig.First, pJoinConfig.Separator)
|
|
310
|
+
: pRecord[pTextField];
|
|
311
|
+
const tmpOption = { Value: pRecord[pValueField], Text: tmpText, Record: pRecord };
|
|
312
|
+
if (pTagField) { tmpOption.Tag = pRecord[pTagField]; }
|
|
313
|
+
return tmpOption;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Fetch-then-merge the join entity for a page of searched records. Collects the unique FK ids the
|
|
318
|
+
* rows carry (`JoinConfig.FKColumn`), issues ONE `FBL~{PKColumn}~INN~<ids>` request against the join
|
|
319
|
+
* entity, and stitches `JoinRecord` + `JoinName` onto each searched row. Resolves the (mutated) same
|
|
320
|
+
* array; on any error or when there's nothing to join, resolves the records un-decorated (the Text
|
|
321
|
+
* gracefully degrades to the base field).
|
|
322
|
+
*
|
|
323
|
+
* @param {Array<any>} pRecords @param {false | Record<string, any>} pJoinConfig
|
|
324
|
+
* @return {Promise<Array<any>>}
|
|
325
|
+
*/
|
|
326
|
+
_decorateRecordsWithJoin(pRecords, pJoinConfig)
|
|
327
|
+
{
|
|
328
|
+
return new Promise((resolve) =>
|
|
329
|
+
{
|
|
330
|
+
if (!pJoinConfig || !Array.isArray(pRecords) || pRecords.length < 1 || !this.pict.EntityProvider) { return resolve(pRecords); }
|
|
331
|
+
const tmpIDs = [];
|
|
332
|
+
const tmpSeen = {};
|
|
333
|
+
for (let i = 0; i < pRecords.length; i++)
|
|
334
|
+
{
|
|
335
|
+
const tmpID = pRecords[i][pJoinConfig.FKColumn];
|
|
336
|
+
if (tmpID !== undefined && tmpID !== null && tmpID !== '' && !tmpSeen[tmpID]) { tmpSeen[tmpID] = true; tmpIDs.push(tmpID); }
|
|
337
|
+
}
|
|
338
|
+
if (tmpIDs.length < 1) { return resolve(pRecords); }
|
|
339
|
+
const tmpFilter = `FBL~${pJoinConfig.PKColumn}~INN~${tmpIDs.join(',')}`;
|
|
340
|
+
this.pict.EntityProvider.getEntitySetPage(pJoinConfig.Entity, tmpFilter, 0, tmpIDs.length,
|
|
341
|
+
(pError, pJoinRecords) =>
|
|
342
|
+
{
|
|
343
|
+
if (pError)
|
|
344
|
+
{
|
|
345
|
+
this.pict.log.warn(`Pict-Section-Picker [${pJoinConfig.Entity}] join fetch failed; showing un-joined text.`, pError);
|
|
346
|
+
return resolve(pRecords);
|
|
347
|
+
}
|
|
348
|
+
const tmpMap = {};
|
|
349
|
+
const tmpJoinList = Array.isArray(pJoinRecords) ? pJoinRecords : [];
|
|
350
|
+
for (let i = 0; i < tmpJoinList.length; i++) { tmpMap[tmpJoinList[i][pJoinConfig.PKColumn]] = tmpJoinList[i]; }
|
|
351
|
+
for (let i = 0; i < pRecords.length; i++)
|
|
352
|
+
{
|
|
353
|
+
const tmpJoinRecord = tmpMap[pRecords[i][pJoinConfig.FKColumn]];
|
|
354
|
+
if (tmpJoinRecord) { pRecords[i].JoinRecord = tmpJoinRecord; pRecords[i].JoinName = tmpJoinRecord[pJoinConfig.DisplayField]; }
|
|
355
|
+
}
|
|
356
|
+
return resolve(pRecords);
|
|
225
357
|
});
|
|
226
358
|
});
|
|
227
359
|
}
|
|
@@ -239,6 +371,8 @@ class PictProviderPicker extends libPictProvider
|
|
|
239
371
|
const tmpValueField = pConfig.ValueField || `ID${tmpEntity}`;
|
|
240
372
|
const tmpTextField = pConfig.TextField || 'Name';
|
|
241
373
|
const tmpMapRecord = (typeof pConfig.MapRecord === 'function') ? pConfig.MapRecord : false;
|
|
374
|
+
const tmpJoinConfig = this._resolveJoinConfig(pConfig);
|
|
375
|
+
const tmpEntityTagField = pConfig.EntityTag || false;
|
|
242
376
|
|
|
243
377
|
return (pValue) => new Promise((resolve) =>
|
|
244
378
|
{
|
|
@@ -250,7 +384,20 @@ class PictProviderPicker extends libPictProvider
|
|
|
250
384
|
(pError, pRecord) =>
|
|
251
385
|
{
|
|
252
386
|
if (pError || !pRecord) { return resolve(null); }
|
|
253
|
-
|
|
387
|
+
const fFinish = () =>
|
|
388
|
+
{
|
|
389
|
+
if (tmpMapRecord) { return resolve(tmpMapRecord(pRecord)); }
|
|
390
|
+
return resolve(this._composeOption(pRecord, tmpValueField, tmpTextField, tmpJoinConfig, tmpEntityTagField));
|
|
391
|
+
};
|
|
392
|
+
// JoinEntity: resolve the single joined record (cached getEntity) for the compound label.
|
|
393
|
+
const tmpFK = tmpJoinConfig ? pRecord[tmpJoinConfig.FKColumn] : null;
|
|
394
|
+
if (!tmpJoinConfig || tmpFK === undefined || tmpFK === null || tmpFK === '') { return fFinish(); }
|
|
395
|
+
this.pict.EntityProvider.getEntity(tmpJoinConfig.Entity, tmpFK,
|
|
396
|
+
(pJoinError, pJoinRecord) =>
|
|
397
|
+
{
|
|
398
|
+
if (!pJoinError && pJoinRecord) { pRecord.JoinRecord = pJoinRecord; pRecord.JoinName = pJoinRecord[tmpJoinConfig.DisplayField]; }
|
|
399
|
+
return fFinish();
|
|
400
|
+
});
|
|
254
401
|
});
|
|
255
402
|
});
|
|
256
403
|
}
|
|
@@ -20,6 +20,10 @@ const _DEFAULT_CONFIGURATION =
|
|
|
20
20
|
Placeholder: 'Select…',
|
|
21
21
|
Searchable: true,
|
|
22
22
|
Options: [],
|
|
23
|
+
// EntityTag badge ordering: false → badge before the label (the select2 default), true → after.
|
|
24
|
+
// The per-option Tag value rides on each source row (`{Value, Text, Tag}`); the entity adapter
|
|
25
|
+
// stamps it from an `EntityTag` field name. With no Tag on a row, no badge renders.
|
|
26
|
+
TagLast: false,
|
|
23
27
|
// Async data source (Phase 2): DataProvider(searchTerm, page) => Promise<{ results:[{Value,Text}], hasMore }>.
|
|
24
28
|
// When a function, the widget searches + paginates through it instead of the static Options list.
|
|
25
29
|
DataProvider: false,
|
|
@@ -74,7 +78,7 @@ const _DEFAULT_CONFIGURATION =
|
|
|
74
78
|
{
|
|
75
79
|
Hash: 'Pict-Section-Picker-Single',
|
|
76
80
|
Template: /*html*/`
|
|
77
|
-
<span class="pps-value{~NE:Record.NoValue^ pps-placeholder~}">{~D:Record.DisplayText~}</span>
|
|
81
|
+
<span class="pps-valuebox">{~TS:Pict-Section-Picker-Tag:Record.TagBeforeSlot~}<span class="pps-value{~NE:Record.NoValue^ pps-placeholder~}">{~D:Record.DisplayText~}</span>{~TS:Pict-Section-Picker-Tag:Record.TagAfterSlot~}</span>
|
|
78
82
|
`
|
|
79
83
|
},
|
|
80
84
|
{
|
|
@@ -95,7 +99,7 @@ const _DEFAULT_CONFIGURATION =
|
|
|
95
99
|
// chip never bubbles up to the control's open/close toggle.
|
|
96
100
|
Hash: 'Pict-Section-Picker-Chip',
|
|
97
101
|
Template: /*html*/`
|
|
98
|
-
<span class="pps-chip"
|
|
102
|
+
<span class="pps-chip">{~TS:Pict-Section-Picker-Tag:Record.TagBeforeSlot~}<span class="pps-chip-text">{~D:Record.Text~}</span>{~TS:Pict-Section-Picker-Tag:Record.TagAfterSlot~}<span class="pps-chip-x" onclick="event.stopPropagation(); _Pict.views['{~D:Record.PickerHash~}'].removeChip('{~D:Record.ValueKey~}')">{~I:Close~}</span></span>
|
|
99
103
|
`
|
|
100
104
|
},
|
|
101
105
|
{
|
|
@@ -155,8 +159,16 @@ const _DEFAULT_CONFIGURATION =
|
|
|
155
159
|
Template: /*html*/`
|
|
156
160
|
<button type="button" class="pps-option{~NE:Record.Selected^ pps-selected~}{~NE:Record.Highlight^ pps-highlight~}" onclick="_Pict.views['{~D:Record.PickerHash~}'].select('{~D:Record.ValueKey~}')">
|
|
157
161
|
<span class="pps-option-check{~NE:Record.NotSelected^ pps-hidden~}">{~I:Check~}</span>
|
|
158
|
-
<span>{~D:Record.Text~}</span>
|
|
162
|
+
{~TS:Pict-Section-Picker-Tag:Record.TagBeforeSlot~}<span class="pps-option-label">{~D:Record.Text~}</span>{~TS:Pict-Section-Picker-Tag:Record.TagAfterSlot~}
|
|
159
163
|
</button>
|
|
164
|
+
`
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
// EntityTag badge — a small code/number pill rendered before or after the label via the
|
|
168
|
+
// TagBeforeSlot / TagAfterSlot single-element-array slots on each option / chip / value record.
|
|
169
|
+
Hash: 'Pict-Section-Picker-Tag',
|
|
170
|
+
Template: /*html*/`
|
|
171
|
+
<span class="pps-tag">{~D:Record.Tag~}</span>
|
|
160
172
|
`
|
|
161
173
|
},
|
|
162
174
|
],
|
|
@@ -249,7 +261,7 @@ class PictViewPicker extends libPictView
|
|
|
249
261
|
{
|
|
250
262
|
if (this._isMulti())
|
|
251
263
|
{
|
|
252
|
-
this._selectedRecords[String(pValue)] = { Value: pResolved.Value !== undefined ? pResolved.Value : pValue, Text: pResolved.Text };
|
|
264
|
+
this._selectedRecords[String(pValue)] = { Value: pResolved.Value !== undefined ? pResolved.Value : pValue, Text: pResolved.Text, Tag: pResolved.Tag };
|
|
253
265
|
this._renderValue();
|
|
254
266
|
}
|
|
255
267
|
else
|
|
@@ -365,7 +377,7 @@ class PictViewPicker extends libPictView
|
|
|
365
377
|
const tmpRow = this._sourceRows().find((pRow) => String(pRow.Value) === String(pVal));
|
|
366
378
|
if (tmpRow)
|
|
367
379
|
{
|
|
368
|
-
this._selectedRecords[String(pVal)] = { Value: tmpRow.Value, Text: tmpRow.Text };
|
|
380
|
+
this._selectedRecords[String(pVal)] = { Value: tmpRow.Value, Text: tmpRow.Text, Tag: tmpRow.Tag };
|
|
369
381
|
return;
|
|
370
382
|
}
|
|
371
383
|
if (this._isAsync() && typeof this.options.ResolveValue === 'function')
|
|
@@ -374,7 +386,7 @@ class PictViewPicker extends libPictView
|
|
|
374
386
|
{
|
|
375
387
|
if (pResolved && pResolved.Text)
|
|
376
388
|
{
|
|
377
|
-
this._selectedRecords[String(pVal)] = { Value: pResolved.Value !== undefined ? pResolved.Value : pVal, Text: pResolved.Text };
|
|
389
|
+
this._selectedRecords[String(pVal)] = { Value: pResolved.Value !== undefined ? pResolved.Value : pVal, Text: pResolved.Text, Tag: pResolved.Tag };
|
|
378
390
|
if (!this._isMulti()) { this._selectedText = pResolved.Text; }
|
|
379
391
|
this._renderValue();
|
|
380
392
|
}
|
|
@@ -383,13 +395,29 @@ class PictViewPicker extends libPictView
|
|
|
383
395
|
});
|
|
384
396
|
}
|
|
385
397
|
|
|
386
|
-
/** @return {Array<{Value:any, Text:string}>} The current option source rows (async results or static Options). */
|
|
398
|
+
/** @return {Array<{Value:any, Text:string, Tag?:any}>} The current option source rows (async results or static Options). */
|
|
387
399
|
_sourceRows()
|
|
388
400
|
{
|
|
389
401
|
if (this._isAsync()) { return this._loadedResults; }
|
|
390
402
|
return Array.isArray(this.options.Options) ? this.options.Options : [];
|
|
391
403
|
}
|
|
392
404
|
|
|
405
|
+
/**
|
|
406
|
+
* Build the EntityTag before/after render slots for a record. Exactly one slot is populated (per the
|
|
407
|
+
* TagLast option) and only when a tag value is present, so a tag-less row renders no badge.
|
|
408
|
+
* @param {any} pTag @param {boolean} pTagLast
|
|
409
|
+
* @return {{TagBeforeSlot:Array<any>, TagAfterSlot:Array<any>}}
|
|
410
|
+
*/
|
|
411
|
+
_tagSlots(pTag, pTagLast)
|
|
412
|
+
{
|
|
413
|
+
const tmpHasTag = (pTag !== undefined && pTag !== null && pTag !== '');
|
|
414
|
+
const tmpSlot = tmpHasTag ? [ { Tag: pTag } ] : [];
|
|
415
|
+
return {
|
|
416
|
+
TagBeforeSlot: (tmpHasTag && !pTagLast) ? tmpSlot : [],
|
|
417
|
+
TagAfterSlot: (tmpHasTag && pTagLast) ? tmpSlot : [],
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
|
|
393
421
|
/**
|
|
394
422
|
* (Re)compute the picker's render state into AppData: the displayed value / chips + the
|
|
395
423
|
* (search-filtered) option list with selected/highlight flags.
|
|
@@ -413,17 +441,18 @@ class PictViewPicker extends libPictView
|
|
|
413
441
|
.filter((pVal) => pVal !== undefined && pVal !== null && pVal !== '')
|
|
414
442
|
.map((pVal) => String(pVal)));
|
|
415
443
|
|
|
444
|
+
const tmpTagLast = !!this.options.TagLast;
|
|
416
445
|
tmpState.Options = tmpSource.map((pOption, pIndex) =>
|
|
417
446
|
{
|
|
418
447
|
const tmpIsSelected = tmpSelectedKeys.has(String(pOption.Value));
|
|
419
|
-
return {
|
|
448
|
+
return Object.assign({
|
|
420
449
|
PickerHash: this.options.PickerHash,
|
|
421
450
|
ValueKey: String(pOption.Value),
|
|
422
451
|
Text: pOption.Text,
|
|
423
452
|
Selected: tmpIsSelected,
|
|
424
453
|
NotSelected: !tmpIsSelected,
|
|
425
454
|
Highlight: (pIndex === this._highlight),
|
|
426
|
-
};
|
|
455
|
+
}, this._tagSlots(pOption.Tag, tmpTagLast));
|
|
427
456
|
});
|
|
428
457
|
|
|
429
458
|
// Cluster options into categories (preserving order), keyed by each source row's optional Group.
|
|
@@ -468,7 +497,9 @@ class PictViewPicker extends libPictView
|
|
|
468
497
|
const tmpChips = tmpValues.map((pVal) =>
|
|
469
498
|
{
|
|
470
499
|
const tmpRecord = this._lookupRecord(pVal);
|
|
471
|
-
return
|
|
500
|
+
return Object.assign(
|
|
501
|
+
{ PickerHash: this.options.PickerHash, ValueKey: String(pVal), Text: tmpRecord ? tmpRecord.Text : String(pVal) },
|
|
502
|
+
this._tagSlots(tmpRecord ? tmpRecord.Tag : undefined, tmpTagLast));
|
|
472
503
|
});
|
|
473
504
|
tmpState.SingleSlot = [];
|
|
474
505
|
tmpState.MultiSlot = [ {
|
|
@@ -482,11 +513,11 @@ class PictViewPicker extends libPictView
|
|
|
482
513
|
const tmpValue = this.getValue();
|
|
483
514
|
const tmpHasValue = (tmpValue !== undefined && tmpValue !== null && tmpValue !== '');
|
|
484
515
|
const tmpSelected = this._lookupRecord(tmpValue);
|
|
485
|
-
tmpState.SingleSlot = [ {
|
|
516
|
+
tmpState.SingleSlot = [ Object.assign({
|
|
486
517
|
PickerHash: this.options.PickerHash,
|
|
487
518
|
DisplayText: tmpSelected ? tmpSelected.Text : (this._selectedText || (tmpHasValue ? String(tmpValue) : this.options.Placeholder)),
|
|
488
519
|
NoValue: !tmpHasValue,
|
|
489
|
-
} ];
|
|
520
|
+
}, this._tagSlots(tmpSelected ? tmpSelected.Tag : undefined, tmpTagLast)) ];
|
|
490
521
|
tmpState.MultiSlot = [];
|
|
491
522
|
}
|
|
492
523
|
return tmpState;
|
|
@@ -496,7 +527,7 @@ class PictViewPicker extends libPictView
|
|
|
496
527
|
* Find the {Value,Text} record for a value: the stored selection record (authoritative for chips /
|
|
497
528
|
* async), else a row in the current source (static Options or loaded results).
|
|
498
529
|
* @param {any} pValue
|
|
499
|
-
* @return {{Value:any, Text:string}|null}
|
|
530
|
+
* @return {{Value:any, Text:string, Tag?:any}|null}
|
|
500
531
|
*/
|
|
501
532
|
_lookupRecord(pValue)
|
|
502
533
|
{
|
|
@@ -726,6 +757,7 @@ class PictViewPicker extends libPictView
|
|
|
726
757
|
if (!this._isMulti())
|
|
727
758
|
{
|
|
728
759
|
this._selectedText = tmpOption.Text;
|
|
760
|
+
this._selectedRecords[String(tmpOption.Value)] = { Value: tmpOption.Value, Text: tmpOption.Text, Tag: tmpOption.Tag };
|
|
729
761
|
this._setValue(tmpOption.Value);
|
|
730
762
|
this._search = '';
|
|
731
763
|
this._open = false;
|
|
@@ -749,7 +781,7 @@ class PictViewPicker extends libPictView
|
|
|
749
781
|
else
|
|
750
782
|
{
|
|
751
783
|
tmpValues.push(tmpOption.Value);
|
|
752
|
-
this._selectedRecords[String(pValueKey)] = { Value: tmpOption.Value, Text: tmpOption.Text };
|
|
784
|
+
this._selectedRecords[String(pValueKey)] = { Value: tmpOption.Value, Text: tmpOption.Text, Tag: tmpOption.Tag };
|
|
753
785
|
}
|
|
754
786
|
this._setValue(tmpValues);
|
|
755
787
|
this._renderValue();
|
|
@@ -789,7 +821,7 @@ class PictViewPicker extends libPictView
|
|
|
789
821
|
{
|
|
790
822
|
this.options.Options.unshift(pRecord);
|
|
791
823
|
}
|
|
792
|
-
this._selectedRecords[String(pRecord.Value)] = { Value: pRecord.Value, Text: pRecord.Text };
|
|
824
|
+
this._selectedRecords[String(pRecord.Value)] = { Value: pRecord.Value, Text: pRecord.Text, Tag: pRecord.Tag };
|
|
793
825
|
|
|
794
826
|
if (this._isMulti())
|
|
795
827
|
{
|
|
@@ -27,6 +27,14 @@ declare class PictInputTypePicker extends PictInputTypePicker_base {
|
|
|
27
27
|
TextField: any;
|
|
28
28
|
PageSize: any;
|
|
29
29
|
Options: any;
|
|
30
|
+
JoinEntity: any;
|
|
31
|
+
JoinField: any;
|
|
32
|
+
JoinEntityValueField: any;
|
|
33
|
+
JoinEntityDisplayField: any;
|
|
34
|
+
JoinEntityFirst: any;
|
|
35
|
+
JoinSeparator: any;
|
|
36
|
+
EntityTag: any;
|
|
37
|
+
TagLast: any;
|
|
30
38
|
BaseFilter: () => string | string[];
|
|
31
39
|
OnChange: any;
|
|
32
40
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Pict-Section-Picker-FormInput.d.ts","sourceRoot":"","sources":["../../source/form/Pict-Section-Picker-FormInput.js"],"names":[],"mappings":";;AAsEA;IAEC,2DAKC;IAGD,yCAAmE;IACnE,uCAA4D;IAC5D,gEAAsG;IACtG,8DAA2F;IAC3F,4DAAuG;IAEvG;;;;;;OAMG;IACH,mCAFW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAkB,MAAM,GAAC,KAAK,CAAC,MAAM,CAAC,CAWnE;IAED,4DAA4D;IAC5D
|
|
1
|
+
{"version":3,"file":"Pict-Section-Picker-FormInput.d.ts","sourceRoot":"","sources":["../../source/form/Pict-Section-Picker-FormInput.js"],"names":[],"mappings":";;AAsEA;IAEC,2DAKC;IAGD,yCAAmE;IACnE,uCAA4D;IAC5D,gEAAsG;IACtG,8DAA2F;IAC3F,4DAAuG;IAEvG;;;;;;OAMG;IACH,mCAFW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAkB,MAAM,GAAC,KAAK,CAAC,MAAM,CAAC,CAWnE;IAED,4DAA4D;IAC5D;;;;;;;;;;;;;;;;;;;;;MA6BC;IAED,8FAA8F;IAC9F,wDAWC;IAED;;;;OAIG;IACH,wEAUC;IAED,2FAKC;IAED;;;;;;OAMG;IACH,0GAFY,OAAO,CAUlB;IAID,oIAMC;IAED,sIAYC;IAED,iFAMC;IAID,qEAAqE;IACrE,2EAD0D,OAAO,CAahE;IAED,gJAIC;IAED,kJAQC;IAED,wGAMC;CACD;;;;AAED;;;;;;;;;;;;;;GAcG;AACH,gDAVW,GAAG,aACH,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAOlB,OAAO,CAwBlB;AApRD;;;;;;;GAOG;AACH,2DAJW,MAAM,iBACN,MAAM,GACL,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAoCrC;AAnDD,kCAAkC;AAClC,sCADW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAO5B"}
|
|
@@ -51,12 +51,76 @@ declare class PictProviderPicker extends libPictProvider {
|
|
|
51
51
|
* evaluated on every search — the generic hook for host-injected CONTEXTUAL scoping (project,
|
|
52
52
|
* tenant, spec-year, …). The module stays agnostic; the host supplies the closure.
|
|
53
53
|
* - MapRecord {function} - optional `(record) => {Value, Text}` mapper (overrides Value/TextField).
|
|
54
|
+
* - JoinEntity {string} - optional second entity to JOIN for a compound display (e.g. a `LineItem`
|
|
55
|
+
* shown with its `Project`). Each searched row must carry the FK (`JoinField`). Because Meadow
|
|
56
|
+
* can't join in one read, this is fetch-then-merge: after the primary page resolves, the unique
|
|
57
|
+
* FK ids drive ONE `FBL~ID{JoinEntity}~INN~<ids>` request, and the joined display field is
|
|
58
|
+
* stitched onto each row (as `Record.JoinName` / `Record.JoinRecord`) + composed into the Text.
|
|
59
|
+
* - JoinField {string} - the FK column ON THE SEARCHED ROW pointing at JoinEntity (default `ID{JoinEntity}`).
|
|
60
|
+
* - JoinEntityValueField {string} - the PK column on JoinEntity to match (default `ID{JoinEntity}`).
|
|
61
|
+
* - JoinEntityDisplayField {string} - the JoinEntity field to display (default `Name`).
|
|
62
|
+
* - JoinEntityFirst {boolean} - put the joined value first in the compound (default `true`):
|
|
63
|
+
* `JoinName - baseText`; when `false`, `baseText - JoinName`.
|
|
64
|
+
* - JoinSeparator {string} - the compound separator (default `' - '`).
|
|
65
|
+
* - EntityTag {string} - optional record field whose value becomes a `Tag` badge on each option
|
|
66
|
+
* (e.g. a `LineItem`'s `ItemNumber`). The picker view renders it as a styled badge alongside the
|
|
67
|
+
* label (ordering via the picker's `TagLast` option). Composes with JoinEntity (tag is outermost).
|
|
54
68
|
* @return {(pSearchTerm: string, pPage: number) => Promise<{results: Array<any>, hasMore: boolean}>}
|
|
55
69
|
*/
|
|
56
70
|
createEntityDataProvider(pConfig: Record<string, any>): (pSearchTerm: string, pPage: number) => Promise<{
|
|
57
71
|
results: Array<any>;
|
|
58
72
|
hasMore: boolean;
|
|
59
73
|
}>;
|
|
74
|
+
/**
|
|
75
|
+
* Resolve the JoinEntity options off an entity-source config into a normalized internal shape, or
|
|
76
|
+
* `false` when no JoinEntity is configured. Centralizes the defaults so the DataProvider and the
|
|
77
|
+
* ResolveValue builders agree.
|
|
78
|
+
*
|
|
79
|
+
* @param {Record<string, any>} pConfig
|
|
80
|
+
* @return {false | {Entity:string, FKColumn:string, PKColumn:string, DisplayField:string, First:boolean, Separator:string}}
|
|
81
|
+
*/
|
|
82
|
+
_resolveJoinConfig(pConfig: Record<string, any>): false | {
|
|
83
|
+
Entity: string;
|
|
84
|
+
FKColumn: string;
|
|
85
|
+
PKColumn: string;
|
|
86
|
+
DisplayField: string;
|
|
87
|
+
First: boolean;
|
|
88
|
+
Separator: string;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Compose a compound display from a base text + a joined value, honoring ordering + separator.
|
|
92
|
+
* Falls back to just the base text when there is no joined value.
|
|
93
|
+
*
|
|
94
|
+
* @param {any} pBaseText @param {any} pJoinText @param {boolean} pFirst @param {string} pSeparator
|
|
95
|
+
* @return {any}
|
|
96
|
+
*/
|
|
97
|
+
_composeJoinedText(pBaseText: any, pJoinText: any, pFirst: boolean, pSeparator: string): any;
|
|
98
|
+
/**
|
|
99
|
+
* Build the picker option `{ Value, Text, Record[, Tag] }` from a (possibly join-decorated) record:
|
|
100
|
+
* the Text honors any JoinEntity compound, and a Tag badge is added from `pTagField` when set. Shared
|
|
101
|
+
* by the DataProvider (per page row) and the ResolveValue (pre-bound value) so they stay consistent.
|
|
102
|
+
*
|
|
103
|
+
* @param {any} pRecord @param {string} pValueField @param {string} pTextField
|
|
104
|
+
* @param {false | Record<string, any>} pJoinConfig @param {string|false} pTagField
|
|
105
|
+
* @return {{Value:any, Text:any, Record:any, Tag?:any}}
|
|
106
|
+
*/
|
|
107
|
+
_composeOption(pRecord: any, pValueField: string, pTextField: string, pJoinConfig: false | Record<string, any>, pTagField: string | false): {
|
|
108
|
+
Value: any;
|
|
109
|
+
Text: any;
|
|
110
|
+
Record: any;
|
|
111
|
+
Tag?: any;
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Fetch-then-merge the join entity for a page of searched records. Collects the unique FK ids the
|
|
115
|
+
* rows carry (`JoinConfig.FKColumn`), issues ONE `FBL~{PKColumn}~INN~<ids>` request against the join
|
|
116
|
+
* entity, and stitches `JoinRecord` + `JoinName` onto each searched row. Resolves the (mutated) same
|
|
117
|
+
* array; on any error or when there's nothing to join, resolves the records un-decorated (the Text
|
|
118
|
+
* gracefully degrades to the base field).
|
|
119
|
+
*
|
|
120
|
+
* @param {Array<any>} pRecords @param {false | Record<string, any>} pJoinConfig
|
|
121
|
+
* @return {Promise<Array<any>>}
|
|
122
|
+
*/
|
|
123
|
+
_decorateRecordsWithJoin(pRecords: Array<any>, pJoinConfig: false | Record<string, any>): Promise<Array<any>>;
|
|
60
124
|
/**
|
|
61
125
|
* Build a `ResolveValue(value) => Promise<{Value,Text}>` for an entity-backed picker, so a
|
|
62
126
|
* pre-bound ID resolves to its display text on first render (fetched + cached by `getEntity`).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Pict-Provider-Picker.d.ts","sourceRoot":"","sources":["../../source/providers/Pict-Provider-Picker.js"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"Pict-Provider-Picker.d.ts","sourceRoot":"","sources":["../../source/providers/Pict-Provider-Picker.js"],"names":[],"mappings":";AA6FA;;;GAGG;AACH;IAEC,2DASC;IAED;;;;;;;;;;;;;;OAcG;IACH,0BAZW,MAAM,WAEN,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAQlB,GAAG,CAqBd;IAED;;;;;;;;;;;OAWG;IACH,iCAJW,KAAK,CAAC,MAAM,CAAC,SACb,MAAM,GACL,MAAM,CAWjB;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgCG;IACH,kCA5BW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GA0BlB,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;QAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAC,CAAC,CAyDnG;IAED;;;;;;;OAOG;IACH,4BAHW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAClB,KAAK,GAAG;QAAC,MAAM,EAAC,MAAM,CAAC;QAAC,QAAQ,EAAC,MAAM,CAAC;QAAC,QAAQ,EAAC,MAAM,CAAC;QAAC,YAAY,EAAC,MAAM,CAAC;QAAC,KAAK,EAAC,OAAO,CAAC;QAAC,SAAS,EAAC,MAAM,CAAA;KAAC,CAe1H;IAED;;;;;;OAMG;IACH,8BAHW,GAAG,aAAoB,GAAG,UAAoB,OAAO,cAAiB,MAAM,GAC3E,GAAG,CAOd;IAED;;;;;;;;OAQG;IACH,wBAJW,GAAG,eAAkB,MAAM,cAAsB,MAAM,eACvD,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,aAAsB,MAAM,GAAC,KAAK,GAC5D;QAAC,KAAK,EAAC,GAAG,CAAC;QAAC,IAAI,EAAC,GAAG,CAAC;QAAC,MAAM,EAAC,GAAG,CAAC;QAAC,GAAG,CAAC,EAAC,GAAG,CAAA;KAAC,CAUtD;IAED;;;;;;;;;OASG;IACH,mCAHW,KAAK,CAAC,GAAG,CAAC,eAAmB,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACvD,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAmC9B;IAED;;;;;;OAMG;IACH,kCAHW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAClB,CAAC,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAqCxC;IAED;;;;;;;;;OASG;IACH,gCAJW,MAAM,WACN,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAClB,GAAG,CAQd;CACD;;;;;AAjVD,kCAAkC;AAClC,sCADW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAO5B"}
|
|
@@ -48,11 +48,22 @@ declare class PictViewPicker extends libPictView {
|
|
|
48
48
|
* @param {Array<any>} pValues
|
|
49
49
|
*/
|
|
50
50
|
_seedSelectedRecords(pValues: Array<any>): void;
|
|
51
|
-
/** @return {Array<{Value:any, Text:string}>} The current option source rows (async results or static Options). */
|
|
51
|
+
/** @return {Array<{Value:any, Text:string, Tag?:any}>} The current option source rows (async results or static Options). */
|
|
52
52
|
_sourceRows(): Array<{
|
|
53
53
|
Value: any;
|
|
54
54
|
Text: string;
|
|
55
|
+
Tag?: any;
|
|
55
56
|
}>;
|
|
57
|
+
/**
|
|
58
|
+
* Build the EntityTag before/after render slots for a record. Exactly one slot is populated (per the
|
|
59
|
+
* TagLast option) and only when a tag value is present, so a tag-less row renders no badge.
|
|
60
|
+
* @param {any} pTag @param {boolean} pTagLast
|
|
61
|
+
* @return {{TagBeforeSlot:Array<any>, TagAfterSlot:Array<any>}}
|
|
62
|
+
*/
|
|
63
|
+
_tagSlots(pTag: any, pTagLast: boolean): {
|
|
64
|
+
TagBeforeSlot: Array<any>;
|
|
65
|
+
TagAfterSlot: Array<any>;
|
|
66
|
+
};
|
|
56
67
|
/**
|
|
57
68
|
* (Re)compute the picker's render state into AppData: the displayed value / chips + the
|
|
58
69
|
* (search-filtered) option list with selected/highlight flags.
|
|
@@ -62,11 +73,12 @@ declare class PictViewPicker extends libPictView {
|
|
|
62
73
|
* Find the {Value,Text} record for a value: the stored selection record (authoritative for chips /
|
|
63
74
|
* async), else a row in the current source (static Options or loaded results).
|
|
64
75
|
* @param {any} pValue
|
|
65
|
-
* @return {{Value:any, Text:string}|null}
|
|
76
|
+
* @return {{Value:any, Text:string, Tag?:any}|null}
|
|
66
77
|
*/
|
|
67
78
|
_lookupRecord(pValue: any): {
|
|
68
79
|
Value: any;
|
|
69
80
|
Text: string;
|
|
81
|
+
Tag?: any;
|
|
70
82
|
} | null;
|
|
71
83
|
/**
|
|
72
84
|
* Load a page of results from the async DataProvider, accumulating (append) or replacing the list.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PictView-Picker.d.ts","sourceRoot":"","sources":["../../source/views/PictView-Picker.js"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"PictView-Picker.d.ts","sourceRoot":"","sources":["../../source/views/PictView-Picker.js"],"names":[],"mappings":";AAyLA;IAEC,2DA0CC;IAlCA,sBAA2E;IAQ3E,eAAkB;IAClB,gBAAiB;IACjB,mBAAoB;IAEpB,sBAAwB;IACxB,cAAc;IACd,kBAAqB;IACrB,kBAAqB;IACrB,iBAAoB;IACpB,6BAAwB;IACxB,mBAAyB;IAGzB,eAAiB;IACjB,qBAA0B;IAc3B,6FAA6F;IAC7F,YADa,OAAO,CAInB;IAED,8EAA8E;IAC9E,YADa,OAAO,CAInB;IAED,4EAA4E;IAC5E,UADa,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAM/B;IAED,qGAAqG;IACrG,8BA+BC;IAED;;;OAGG;IACH,YAHY,GAAG,CAgBd;IAED;;;;OAIG;IACH,kBAFW,GAAG,QA6Bb;IAvBC,YAAoB;IAyBtB;;;;;;OAMG;IACH,iBAHW,GAAG,GACF,cAAc,CAqBzB;IAED;;;;OAIG;IACH,8BAFW,KAAK,CAAC,GAAG,CAAC,QA0BpB;IAED,4HAA4H;IAC5H,eADa,KAAK,CAAC;QAAC,KAAK,EAAC,GAAG,CAAC;QAAC,IAAI,EAAC,MAAM,CAAC;QAAC,GAAG,CAAC,EAAC,GAAG,CAAA;KAAC,CAAC,CAKrD;IAED;;;;;OAKG;IACH,gBAHW,GAAG,YAAe,OAAO,GACxB;QAAC,aAAa,EAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAAC,YAAY,EAAC,KAAK,CAAC,GAAG,CAAC,CAAA;KAAC,CAU9D;IAED;;;OAGG;IACH,mCAmGC;IAED;;;;;OAKG;IACH,sBAHW,GAAG,GACF;QAAC,KAAK,EAAC,GAAG,CAAC;QAAC,IAAI,EAAC,MAAM,CAAC;QAAC,GAAG,CAAC,EAAC,GAAG,CAAA;KAAC,GAAC,IAAI,CAQlD;IAED;;;;OAIG;IACH,iBAHW,MAAM,WACN,OAAO,QA4BjB;IAWD,uCAAuC;IACvC,0BAIC;IAED,+EAA+E;IAC/E,gCAWC;IAED,kDAAkD;IAClD,aASC;IAED;;;;OAIG;IACH,qBAgCC;IAED,0DAA0D;IAC1D,iBAMC;IAED,0BAA0B;IAC1B,cAKC;IAED,6DAA6D;IAC7D,mBAIC;IAED,kFAAkF;IAClF,oBAKC;IAED;sGACkG;IAClG,qBAKC;IAED,2EAA2E;IAC3E,eADY,MAAM,QAejB;IAED,iGAAiG;IACjG,+BAgCC;IAED;;;;OAIG;IACH,kBAFW,MAAM,QA6ChB;IAED,sGAAsG;IACtG,sBADa,KAAK,CAAC;QAAC,KAAK,EAAC,GAAG,CAAC;QAAC,IAAI,EAAC,MAAM,CAAA;KAAC,CAAC,CAI3C;IAED;;;;OAIG;IACH,yBA6CC;IAED,oFAAoF;IACpF,iCAWC;CAWD;;;;;AA32BD,kCAAkC;AAClC,sCADW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAqL5B"}
|