pict-section-picker 1.0.0 → 1.1.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 +18 -0
- package/form.js +5 -0
- package/package.json +12 -2
- package/source/form/Pict-Section-Picker-FormInput.js +299 -0
- package/source/providers/Pict-Provider-Picker.js +29 -5
- package/source/views/PictView-Picker.js +99 -0
- package/types/form/Pict-Section-Picker-FormInput.d.ts +89 -0
- package/types/form/Pict-Section-Picker-FormInput.d.ts.map +1 -0
- package/types/providers/Pict-Provider-Picker.d.ts +4 -1
- package/types/providers/Pict-Provider-Picker.d.ts.map +1 -1
- package/types/views/PictView-Picker.d.ts +20 -0
- package/types/views/PictView-Picker.d.ts.map +1 -1
package/README.md
CHANGED
|
@@ -162,6 +162,24 @@ OnCreate: (pTerm) =>
|
|
|
162
162
|
| `OnCreate` | — | `(term) => {Value, Text}` to enable creatable entries. |
|
|
163
163
|
| `OnChange` | — | Called after a selection: single → `(value, record)`, multi → `(values, records)`. |
|
|
164
164
|
|
|
165
|
+
## View methods
|
|
166
|
+
|
|
167
|
+
Call these on the picker view instance — `this.pict.views['<hash>']`:
|
|
168
|
+
|
|
169
|
+
| Method | Description |
|
|
170
|
+
|--------|-------------|
|
|
171
|
+
| `render()` | Paint (or repaint) the control into its destination. |
|
|
172
|
+
| `getValue()` | The current selection — a scalar in single mode, an array of values in multi mode. |
|
|
173
|
+
| `setValue(pValue)` | Set the selection programmatically — the supported counterpart to `getValue()`. Single mode takes a scalar; multi mode takes an array (or a csv string). Writes through to the bound address(es), resolves the display label of any unknown value (from the loaded options, else via `ResolveValue` in async mode), and repaints. Does **not** fire `OnChange` — it is a programmatic set (e.g. a host marshaling a form value into the control), not a user pick. Returns the view for chaining. |
|
|
174
|
+
| `getSelectedRecords()` | (multi) The full `{Value, Text}` record list for the current selection. |
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
const tmpPicker = this.pict.views['AuthorPicker'];
|
|
178
|
+
tmpPicker.setValue(141); // single: select author 141 (label resolves via ResolveValue if async)
|
|
179
|
+
tmpPicker.setValue([ 2, 10, 141 ]); // multi: select these values (array or "2,10,141" csv both accepted)
|
|
180
|
+
const tmpSelected = tmpPicker.getValue();
|
|
181
|
+
```
|
|
182
|
+
|
|
165
183
|
## Theming
|
|
166
184
|
|
|
167
185
|
The widget paints from `--theme-color-*` tokens with sensible hex fallbacks, so it inherits the host app's theme. Relevant tokens: `--theme-color-brand-primary`, `--theme-color-text-primary`, `--theme-color-text-muted`, `--theme-color-border-default`, `--theme-color-border-light`, `--theme-color-border-strong`, `--theme-color-background-primary`, `--theme-color-background-panel`, `--theme-color-background-tertiary`.
|
package/form.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Sub-path entry: `require('pict-section-picker/form')`.
|
|
2
|
+
//
|
|
3
|
+
// The pict-section-form input-type adapter — kept off the package's main entry so the picker core
|
|
4
|
+
// stays usable without pict-section-form (which is an OPTIONAL peer dependency, required only here).
|
|
5
|
+
module.exports = require('./source/form/Pict-Section-Picker-FormInput.js');
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pict-section-picker",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.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",
|
|
7
7
|
"files": [
|
|
8
8
|
"source",
|
|
9
|
-
"types"
|
|
9
|
+
"types",
|
|
10
|
+
"form.js"
|
|
10
11
|
],
|
|
11
12
|
"scripts": {
|
|
12
13
|
"test": "npx mocha -u tdd -R spec",
|
|
@@ -48,11 +49,20 @@
|
|
|
48
49
|
"pict-provider": "^1.0.13",
|
|
49
50
|
"pict-view": "^1.0.68"
|
|
50
51
|
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"pict-section-form": ">=1.0.0"
|
|
54
|
+
},
|
|
55
|
+
"peerDependenciesMeta": {
|
|
56
|
+
"pict-section-form": {
|
|
57
|
+
"optional": true
|
|
58
|
+
}
|
|
59
|
+
},
|
|
51
60
|
"devDependencies": {
|
|
52
61
|
"@types/mocha": "^10.0.10",
|
|
53
62
|
"@types/node": "^16.18.126",
|
|
54
63
|
"browser-env": "^3.3.0",
|
|
55
64
|
"pict": "^1.0.372",
|
|
65
|
+
"pict-section-form": "^1.0.0",
|
|
56
66
|
"quackage": "^1.3.0",
|
|
57
67
|
"typescript": "^5.9.3"
|
|
58
68
|
}
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pict-section-form input-type adapter for pict-section-picker.
|
|
3
|
+
*
|
|
4
|
+
* Renders a picker widget into a dynamic-form cell — the host-agnostic replacement for a select2
|
|
5
|
+
* entity input. Registered as a pict-section-form InputType (default name `Picker`); a host opts a
|
|
6
|
+
* field in with `PictForm.InputType: 'Picker'` (+ Entity / SearchFields / Multiple / …). Used by the
|
|
7
|
+
* pict-section-recordset entity filters and by document forms alike.
|
|
8
|
+
*
|
|
9
|
+
* Contextual scoping (project / spec-year / tenant / …) stays host configuration: the descriptor may
|
|
10
|
+
* carry a `PictForm.GetContextScopeFilter()` hook, OR a host subclass overrides
|
|
11
|
+
* `getContextualSearchFilters(pInput)`. Either way the module never learns what the context means.
|
|
12
|
+
*
|
|
13
|
+
* Requires `pict-section-form` (an OPTIONAL peer dependency — only loaded when you require this file)
|
|
14
|
+
* and the `Pict-Section-Picker` provider registered on the pict instance.
|
|
15
|
+
*/
|
|
16
|
+
const libPictInputExtension = require('pict-section-form').PictInputExtensionProvider;
|
|
17
|
+
|
|
18
|
+
/** @type {Record<string, any>} */
|
|
19
|
+
const _DEFAULT_CONFIGURATION =
|
|
20
|
+
{
|
|
21
|
+
ProviderIdentifier: 'Pict-Input-Picker',
|
|
22
|
+
AutoInitialize: true,
|
|
23
|
+
AutoInitializeOrdinal: 0,
|
|
24
|
+
AutoSolveWithApp: false,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Build the InputType metatemplate entries (a hidden informary input + a host element the picker
|
|
29
|
+
* renders into) for a given InputType name + provider hash. Injected via injectTemplateSet.
|
|
30
|
+
*
|
|
31
|
+
* @param {string} pInputTypeName - e.g. 'Picker'.
|
|
32
|
+
* @param {string} pProviderHash - the input-extension provider service hash to auto-attach.
|
|
33
|
+
* @return {Array<Record<string, any>>}
|
|
34
|
+
*/
|
|
35
|
+
const buildPickerInputTemplates = (pInputTypeName, pProviderHash) =>
|
|
36
|
+
[
|
|
37
|
+
{
|
|
38
|
+
// Mirror the host's DEFAULT input metatemplate structure exactly — a label span + the control
|
|
39
|
+
// where the <input>/<select> would be — so the picker inherits the host's filter/form chrome
|
|
40
|
+
// (label style, spacing, and the row's flex-end trash alignment) instead of inventing its own.
|
|
41
|
+
HashPostfix: `-Template-Input-InputType-${pInputTypeName}`,
|
|
42
|
+
DefaultInputExtensions: [ pProviderHash ],
|
|
43
|
+
Template: /*html*/`
|
|
44
|
+
<!-- InputType ${pInputTypeName} {~D:Record.Hash~} {~D:Record.DataType~} -->
|
|
45
|
+
<input type="hidden" id="{~D:Record.Macro.RawHTMLID~}" tabindex="-1" {~D:Record.Macro.InputFullProperties~} {~D:Record.Macro.InputChangeHandler~} value="" />
|
|
46
|
+
<span>{~D:Record.Name~}:</span> <div class="pps-form-host" id="PICKER-FOR-{~D:Record.Macro.RawHTMLID~}"></div>`,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
HashPostfix: `-VerticalTemplate-Input-InputType-${pInputTypeName}`,
|
|
50
|
+
DefaultInputExtensions: [ pProviderHash ],
|
|
51
|
+
Template: /*html*/`
|
|
52
|
+
<!-- InputType ${pInputTypeName} {~D:Record.Hash~} {~D:Record.DataType~} -->
|
|
53
|
+
<input type="hidden" id="{~D:Record.Macro.RawHTMLID~}" tabindex="-1" {~D:Record.Macro.InputFullProperties~} {~D:Record.Macro.InputChangeHandler~} value="" />
|
|
54
|
+
<span>{~D:Record.Name~}:</span> <div class="pps-form-host" id="PICKER-FOR-{~D:Record.Macro.RawHTMLID~}"></div>`,
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
HashPostfix: `-TabularTemplate-Begin-Input-InputType-${pInputTypeName}`,
|
|
58
|
+
DefaultInputExtensions: [ pProviderHash ],
|
|
59
|
+
Template: /*html*/`
|
|
60
|
+
<input type="hidden" id="PICKER-TABULAR-DATA-{~D:Record.Macro.RawHTMLID~}-{~D:Context[2].Key~}" tabindex="-1" {~D:Record.Macro.InformaryTabular~} `,
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
HashPostfix: `-TabularTemplate-End-Input-InputType-${pInputTypeName}`,
|
|
64
|
+
DefaultInputExtensions: [ pProviderHash ],
|
|
65
|
+
Template: /*html*/`
|
|
66
|
+
value="" />
|
|
67
|
+
<div class="pps-form-host" id="PICKER-TABULAR-{~D:Record.Macro.RawHTMLID~}-{~D:Context[2].Key~}"></div>`,
|
|
68
|
+
},
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
class PictInputTypePicker extends libPictInputExtension
|
|
72
|
+
{
|
|
73
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
74
|
+
{
|
|
75
|
+
super(pFable, Object.assign({}, _DEFAULT_CONFIGURATION, pOptions), pServiceHash);
|
|
76
|
+
/** @type {any} */
|
|
77
|
+
this.pict;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Visible host + picker-view-hash ids. Must match the metatemplate element ids above.
|
|
81
|
+
getPickerHostID(pRawHTMLID) { return `#PICKER-FOR-${pRawHTMLID}`; }
|
|
82
|
+
getPickerHash(pRawHTMLID) { return `Picker-${pRawHTMLID}`; }
|
|
83
|
+
getTabularPickerHostID(pRawHTMLID, pRowIndex) { return `#PICKER-TABULAR-${pRawHTMLID}-${pRowIndex}`; }
|
|
84
|
+
getTabularPickerHash(pRawHTMLID, pRowIndex) { return `Picker-${pRawHTMLID}-${pRowIndex}`; }
|
|
85
|
+
getTabularHiddenID(pRawHTMLID, pRowIndex) { return `#PICKER-TABULAR-DATA-${pRawHTMLID}-${pRowIndex}`; }
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Overridable: extra FoxHound scope stanza(s) AND-applied to the entity search. Default reads the
|
|
89
|
+
* descriptor's `GetContextScopeFilter()` hook (set by the host / recordset filter base), else its
|
|
90
|
+
* static `BaseFilter`. Host subclasses override this to read app state (project / spec-year / …).
|
|
91
|
+
*
|
|
92
|
+
* @param {Record<string, any>} pInput @return {string|Array<string>}
|
|
93
|
+
*/
|
|
94
|
+
getContextualSearchFilters(pInput)
|
|
95
|
+
{
|
|
96
|
+
const tmpHook = pInput && pInput.PictForm && pInput.PictForm.GetContextScopeFilter;
|
|
97
|
+
if (typeof tmpHook === 'function')
|
|
98
|
+
{
|
|
99
|
+
try { return tmpHook() || ''; }
|
|
100
|
+
catch (pError) { this.pict.log.warn(`Pict-Input-Picker: GetContextScopeFilter threw.`, pError); return ''; }
|
|
101
|
+
}
|
|
102
|
+
return (pInput && pInput.PictForm && pInput.PictForm.BaseFilter) || '';
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Build the picker config from a form input descriptor. */
|
|
106
|
+
_buildPickerConfig(pInput, pHostSelector, fOnChange)
|
|
107
|
+
{
|
|
108
|
+
const tmpPF = pInput.PictForm || {};
|
|
109
|
+
return {
|
|
110
|
+
DestinationAddress: pHostSelector,
|
|
111
|
+
Mode: tmpPF.Multiple ? 'multi' : 'single',
|
|
112
|
+
Placeholder: tmpPF.Placeholder || (tmpPF.Entity ? `Select ${tmpPF.Entity}…` : 'Select…'),
|
|
113
|
+
Searchable: (tmpPF.Searchable !== false),
|
|
114
|
+
Entity: tmpPF.Entity,
|
|
115
|
+
SearchFields: tmpPF.SearchFields,
|
|
116
|
+
ValueField: tmpPF.ValueField,
|
|
117
|
+
TextField: tmpPF.TextField,
|
|
118
|
+
PageSize: tmpPF.PageSize || 20,
|
|
119
|
+
Options: tmpPF.Options || [],
|
|
120
|
+
// Per-search contextual scope — the generic hook the host fills.
|
|
121
|
+
BaseFilter: () => this.getContextualSearchFilters(pInput),
|
|
122
|
+
OnChange: fOnChange,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** Instantiate (or reuse) the picker view for a config — entity-backed when Entity is set. */
|
|
127
|
+
_instantiatePicker(pPickerHash, pConfig)
|
|
128
|
+
{
|
|
129
|
+
const tmpProvider = this.pict.providers['Pict-Section-Picker'];
|
|
130
|
+
if (!tmpProvider)
|
|
131
|
+
{
|
|
132
|
+
this.pict.log.warn('Pict-Input-Picker: the Pict-Section-Picker provider is not registered.');
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
return pConfig.Entity
|
|
136
|
+
? tmpProvider.createEntityPicker(pPickerHash, pConfig)
|
|
137
|
+
: tmpProvider.createPicker(pPickerHash, pConfig);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Write a picker value into the form: csv to the hidden informary input (+ dataChanged), plus the
|
|
142
|
+
* raw array to `PictForm.ValueArrayAddress` when set (the recordset filter reads Values as an
|
|
143
|
+
* array). The csv-vs-array bridge lives HERE (generic) instead of in each host.
|
|
144
|
+
*/
|
|
145
|
+
_commit(pView, pInput, pValue, pHTMLSelector)
|
|
146
|
+
{
|
|
147
|
+
const tmpCSV = Array.isArray(pValue) ? pValue.join(',') : (pValue === undefined || pValue === null ? '' : pValue);
|
|
148
|
+
this.pict.ContentAssignment.assignContent(pHTMLSelector, tmpCSV);
|
|
149
|
+
if (pInput.PictForm && pInput.PictForm.ValueArrayAddress && pView.Bundle)
|
|
150
|
+
{
|
|
151
|
+
const tmpArray = Array.isArray(pValue) ? pValue : (tmpCSV === '' ? [] : String(tmpCSV).split(','));
|
|
152
|
+
this.pict.manifest.setValueAtAddress(pView.Bundle, pInput.PictForm.ValueArrayAddress, tmpArray);
|
|
153
|
+
}
|
|
154
|
+
pView.dataChanged(pInput.Hash);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
_commitTabular(pView, pInput, pValue, pHiddenID, pRowIndex)
|
|
158
|
+
{
|
|
159
|
+
const tmpCSV = Array.isArray(pValue) ? pValue.join(',') : (pValue === undefined || pValue === null ? '' : pValue);
|
|
160
|
+
this.pict.ContentAssignment.assignContent(pHiddenID, tmpCSV);
|
|
161
|
+
pView.dataChangedTabular(pInput.PictForm.GroupIndex, pInput.PictForm.InputIndex, pRowIndex);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Idempotently mount (or reuse) the picker into its host element + seed its value. Called from both
|
|
166
|
+
* onInputInitialize and onDataMarshalToForm because, in the async-virtual filter render, the host
|
|
167
|
+
* element only exists in the real DOM by the marshal pass — whichever hook fires post-DOM wins, and
|
|
168
|
+
* re-calls are harmless (the picker view is reused by hash).
|
|
169
|
+
* @return {boolean} true if the picker is mounted.
|
|
170
|
+
*/
|
|
171
|
+
_mountPicker(pView, pInput, pValue, pHostSelector, pPickerHash, fOnChange)
|
|
172
|
+
{
|
|
173
|
+
if (!this.pict.ContentAssignment.getElement(pHostSelector)?.[0]) { return false; }
|
|
174
|
+
const tmpView = this._instantiatePicker(pPickerHash, this._buildPickerConfig(pInput, pHostSelector, fOnChange));
|
|
175
|
+
if (!tmpView) { return false; }
|
|
176
|
+
tmpView.render();
|
|
177
|
+
tmpView.setValue(pValue);
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// --- non-tabular lifecycle ---
|
|
182
|
+
|
|
183
|
+
onInputInitialize(pView, pGroup, pRow, pInput, pValue, pHTMLSelector, pTransactionGUID)
|
|
184
|
+
{
|
|
185
|
+
const tmpRaw = pInput.Macro.RawHTMLID;
|
|
186
|
+
this._mountPicker(pView, pInput, pValue, this.getPickerHostID(tmpRaw), this.getPickerHash(tmpRaw),
|
|
187
|
+
(pNewValue) => this._commit(pView, pInput, pNewValue, pInput.Macro.HTMLSelector));
|
|
188
|
+
return super.onInputInitialize(pView, pGroup, pRow, pInput, pValue, pHTMLSelector, pTransactionGUID);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
onDataMarshalToForm(pView, pGroup, pRow, pInput, pValue, pHTMLSelector, pTransactionGUID)
|
|
192
|
+
{
|
|
193
|
+
const tmpRaw = pInput.Macro.RawHTMLID;
|
|
194
|
+
const tmpPickerHash = this.getPickerHash(tmpRaw);
|
|
195
|
+
// Mount if it isn't already (post-DOM hook), else just re-seed the value.
|
|
196
|
+
if (!this._mountPicker(pView, pInput, pValue, this.getPickerHostID(tmpRaw), tmpPickerHash,
|
|
197
|
+
(pNewValue) => this._commit(pView, pInput, pNewValue, pInput.Macro.HTMLSelector)))
|
|
198
|
+
{
|
|
199
|
+
const tmpView = this.pict.views[tmpPickerHash];
|
|
200
|
+
if (tmpView) { tmpView.setValue(pValue); }
|
|
201
|
+
}
|
|
202
|
+
return super.onDataMarshalToForm(pView, pGroup, pRow, pInput, pValue, pHTMLSelector, pTransactionGUID);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
onDataRequest(pView, pInput, pValue, pHTMLSelector)
|
|
206
|
+
{
|
|
207
|
+
const tmpView = this.pict.views[this.getPickerHash(pInput.Macro.RawHTMLID)];
|
|
208
|
+
const tmpVal = tmpView ? tmpView.getValue() : pValue;
|
|
209
|
+
this._commit(pView, pInput, tmpVal, pHTMLSelector);
|
|
210
|
+
return super.onDataRequest(pView, pInput, tmpVal, pHTMLSelector);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// --- tabular lifecycle (one picker view instance per (input, row)) ---
|
|
214
|
+
|
|
215
|
+
/** Idempotent tabular mount (see _mountPicker). @return {boolean} */
|
|
216
|
+
_mountPickerTabular(pView, pInput, pValue, pRowIndex)
|
|
217
|
+
{
|
|
218
|
+
const tmpRaw = pInput.Macro.RawHTMLID;
|
|
219
|
+
const tmpHostSelector = this.getTabularPickerHostID(tmpRaw, pRowIndex);
|
|
220
|
+
if (!this.pict.ContentAssignment.getElement(tmpHostSelector)?.[0]) { return false; }
|
|
221
|
+
const tmpHiddenID = this.getTabularHiddenID(tmpRaw, pRowIndex);
|
|
222
|
+
const tmpView = this._instantiatePicker(this.getTabularPickerHash(tmpRaw, pRowIndex),
|
|
223
|
+
this._buildPickerConfig(pInput, tmpHostSelector, (pNewValue) => this._commitTabular(pView, pInput, pNewValue, tmpHiddenID, pRowIndex)));
|
|
224
|
+
if (!tmpView) { return false; }
|
|
225
|
+
tmpView.render();
|
|
226
|
+
tmpView.setValue(pValue);
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
onInputInitializeTabular(pView, pGroup, pInput, pValue, pHTMLSelector, pRowIndex, pTransactionGUID)
|
|
231
|
+
{
|
|
232
|
+
this._mountPickerTabular(pView, pInput, pValue, pRowIndex);
|
|
233
|
+
return super.onInputInitializeTabular(pView, pGroup, pInput, pValue, pHTMLSelector, pRowIndex, pTransactionGUID);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
onDataMarshalToFormTabular(pView, pGroup, pInput, pValue, pHTMLSelector, pRowIndex, pTransactionGUID)
|
|
237
|
+
{
|
|
238
|
+
if (!this._mountPickerTabular(pView, pInput, pValue, pRowIndex))
|
|
239
|
+
{
|
|
240
|
+
const tmpView = this.pict.views[this.getTabularPickerHash(pInput.Macro.RawHTMLID, pRowIndex)];
|
|
241
|
+
if (tmpView) { tmpView.setValue(pValue); }
|
|
242
|
+
}
|
|
243
|
+
return super.onDataMarshalToFormTabular(pView, pGroup, pInput, pValue, pHTMLSelector, pRowIndex, pTransactionGUID);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
onDataRequestTabular(pView, pInput, pValue, pHTMLSelector, pRowIndex)
|
|
247
|
+
{
|
|
248
|
+
const tmpView = this.pict.views[this.getTabularPickerHash(pInput.Macro.RawHTMLID, pRowIndex)];
|
|
249
|
+
const tmpVal = tmpView ? tmpView.getValue() : pValue;
|
|
250
|
+
this._commitTabular(pView, pInput, tmpVal, this.getTabularHiddenID(pInput.Macro.RawHTMLID, pRowIndex), pRowIndex);
|
|
251
|
+
return super.onDataRequestTabular(pView, pInput, tmpVal, pHTMLSelector, pRowIndex);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Register the Picker InputType on a pict instance: the input-extension provider + its metatemplate(s).
|
|
257
|
+
* Idempotent. Requires `pict-section-form` loaded (PictFormSectionDefaultTemplateProvider present) and
|
|
258
|
+
* the `Pict-Section-Picker` provider registered.
|
|
259
|
+
*
|
|
260
|
+
* @param {any} pPict - the pict instance.
|
|
261
|
+
* @param {Record<string, any>} [pOptions]
|
|
262
|
+
* - InputTypeName {string} - the InputType string (default 'Picker').
|
|
263
|
+
* - ProviderHash {string} - the input-extension provider service hash (default 'Pict-Input-Picker').
|
|
264
|
+
* - ProviderClass {Function} - provider class to register (default PictInputTypePicker; a host
|
|
265
|
+
* passes a subclass that overrides getContextualSearchFilters for its scoping).
|
|
266
|
+
* - TemplatePrefix {string|Array<string>} - the form template prefix(es) to inject the metatemplate
|
|
267
|
+
* under (default 'Pict-MT-Base'; Headlight uses its theme prefixes).
|
|
268
|
+
* @return {boolean} true if registered.
|
|
269
|
+
*/
|
|
270
|
+
const registerPickerInputType = (pPict, pOptions) =>
|
|
271
|
+
{
|
|
272
|
+
const tmpOptions = pOptions || {};
|
|
273
|
+
const tmpInputTypeName = tmpOptions.InputTypeName || 'Picker';
|
|
274
|
+
const tmpProviderHash = tmpOptions.ProviderHash || 'Pict-Input-Picker';
|
|
275
|
+
const tmpProviderClass = tmpOptions.ProviderClass || PictInputTypePicker;
|
|
276
|
+
const tmpPrefixes = Array.isArray(tmpOptions.TemplatePrefix) ? tmpOptions.TemplatePrefix : [ tmpOptions.TemplatePrefix || 'Pict-MT-Base' ];
|
|
277
|
+
|
|
278
|
+
if (!pPict.providers[tmpProviderHash])
|
|
279
|
+
{
|
|
280
|
+
pPict.addProvider(tmpProviderHash, Object.assign({}, _DEFAULT_CONFIGURATION, { ProviderIdentifier: tmpProviderHash }), tmpProviderClass);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const tmpTemplateProvider = pPict.providers.PictFormSectionDefaultTemplateProvider;
|
|
284
|
+
if (!tmpTemplateProvider || typeof tmpTemplateProvider.injectTemplateSet !== 'function')
|
|
285
|
+
{
|
|
286
|
+
pPict.log.warn('Pict-Input-Picker: PictFormSectionDefaultTemplateProvider not available; cannot register the Picker metatemplate (is pict-section-form loaded?).');
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
const tmpTemplates = buildPickerInputTemplates(tmpInputTypeName, tmpProviderHash);
|
|
290
|
+
tmpPrefixes.forEach((pPrefix) => tmpTemplateProvider.injectTemplateSet({ TemplatePrefix: pPrefix, Templates: tmpTemplates }));
|
|
291
|
+
return true;
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
module.exports = PictInputTypePicker;
|
|
295
|
+
|
|
296
|
+
module.exports.PictInputTypePicker = PictInputTypePicker;
|
|
297
|
+
module.exports.registerPickerInputType = registerPickerInputType;
|
|
298
|
+
module.exports.buildPickerInputTemplates = buildPickerInputTemplates;
|
|
299
|
+
module.exports.default_configuration = _DEFAULT_CONFIGURATION;
|
|
@@ -31,9 +31,15 @@ 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
|
-
/* Transparent full-viewport backdrop: closes on outside click (no document listener).
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
/* Transparent full-viewport backdrop: closes on outside click (no document listener). Only present
|
|
35
|
+
while OPEN — otherwise a fixed full-viewport layer would swallow every click on the page. When open,
|
|
36
|
+
the control is raised above it so its chips/× stay clickable; the dropdown sits above both. */
|
|
37
|
+
.pps-backdrop { position: fixed; inset: 0; z-index: 0; display: none; }
|
|
38
|
+
.pps.pps-open .pps-backdrop { display: block; }
|
|
39
|
+
.pps.pps-open .pps-control { position: relative; z-index: 1; }
|
|
40
|
+
/* Fixed (viewport-anchored) + JS-positioned in open(), so no ancestor's overflow:hidden — a card, a
|
|
41
|
+
slide-out drawer, a scroll pane — can ever clip the dropdown, whatever the host's layout. */
|
|
42
|
+
.pps-pop { position: fixed; z-index: 40; min-width: 200px; display: none; }
|
|
37
43
|
.pps.pps-open .pps-pop { display: block; }
|
|
38
44
|
.pps-panel { position: relative; z-index: 1; display: flex; flex-direction: column; max-height: min(60vh, 360px);
|
|
39
45
|
background: var(--theme-color-background-panel, #fff); border: 1px solid var(--theme-color-border-default, #d7dce3);
|
|
@@ -60,6 +66,10 @@ const _PickerCSS = /*css*/`
|
|
|
60
66
|
padding: 0.45rem 0.6rem; border: none; border-radius: 6px; background: transparent; color: var(--theme-color-brand-primary, #156dd1); font-weight: 600; }
|
|
61
67
|
.pps-create:hover { background: var(--theme-color-background-tertiary, #eceef2); }
|
|
62
68
|
.pps-create-ic { flex: 0 0 auto; display: inline-flex; }
|
|
69
|
+
|
|
70
|
+
/* Form-input adapter (pict-section-picker/form): the picker host fills its row like the host's
|
|
71
|
+
native inputs (width:100% forces it to wrap below the label span + fill, matching a scalar input). */
|
|
72
|
+
.pps-form-host { flex: 1 1 100%; min-width: 0; width: 100%; }
|
|
63
73
|
`;
|
|
64
74
|
|
|
65
75
|
/** @type {Record<string, any>} */
|
|
@@ -159,7 +169,10 @@ class PictProviderPicker extends libPictProvider
|
|
|
159
169
|
* - TextField {string} - record field used as the option Text (default `Name`).
|
|
160
170
|
* - PageSize {number} - records per page (default 20).
|
|
161
171
|
* - Sort {string} - optional field to sort ascending (adds `FSF~<field>~ASC~0`).
|
|
162
|
-
* - BaseFilter {string} - optional always-applied FoxHound filter (AND),
|
|
172
|
+
* - BaseFilter {string|Array<string>|function} - optional always-applied FoxHound filter (AND),
|
|
173
|
+
* e.g. `FBV~IDCustomer~EQ~1`. May be a **function** `(searchTerm, page) => string|string[]`
|
|
174
|
+
* evaluated on every search — the generic hook for host-injected CONTEXTUAL scoping (project,
|
|
175
|
+
* tenant, spec-year, …). The module stays agnostic; the host supplies the closure.
|
|
163
176
|
* - MapRecord {function} - optional `(record) => {Value, Text}` mapper (overrides Value/TextField).
|
|
164
177
|
* @return {(pSearchTerm: string, pPage: number) => Promise<{results: Array<any>, hasMore: boolean}>}
|
|
165
178
|
*/
|
|
@@ -171,7 +184,7 @@ class PictProviderPicker extends libPictProvider
|
|
|
171
184
|
const tmpTextField = pConfig.TextField || 'Name';
|
|
172
185
|
const tmpPageSize = pConfig.PageSize || 20;
|
|
173
186
|
const tmpSort = pConfig.Sort || false;
|
|
174
|
-
const
|
|
187
|
+
const tmpBaseFilterConfig = pConfig.BaseFilter || '';
|
|
175
188
|
const tmpMapRecord = (typeof pConfig.MapRecord === 'function') ? pConfig.MapRecord : false;
|
|
176
189
|
|
|
177
190
|
return (pSearchTerm, pPage) => new Promise((resolve, reject) =>
|
|
@@ -181,6 +194,17 @@ class PictProviderPicker extends libPictProvider
|
|
|
181
194
|
return reject(new Error('Pict-Section-Picker: pict.EntityProvider is not available for entity-backed pickers.'));
|
|
182
195
|
}
|
|
183
196
|
|
|
197
|
+
// Resolve the base filter at SEARCH time. A function form lets the host inject contextual
|
|
198
|
+
// scoping (e.g. "only this project's line items") without the module knowing the context;
|
|
199
|
+
// it can return a single stanza, an array of stanzas, or nothing.
|
|
200
|
+
let tmpBaseFilter = tmpBaseFilterConfig;
|
|
201
|
+
if (typeof tmpBaseFilterConfig === 'function')
|
|
202
|
+
{
|
|
203
|
+
try { tmpBaseFilter = tmpBaseFilterConfig(pSearchTerm, pPage); }
|
|
204
|
+
catch (pScopeError) { this.pict.log.warn(`Pict-Section-Picker [${tmpEntity}] BaseFilter() threw; ignoring contextual scope.`, pScopeError); tmpBaseFilter = ''; }
|
|
205
|
+
}
|
|
206
|
+
if (Array.isArray(tmpBaseFilter)) { tmpBaseFilter = tmpBaseFilter.filter(Boolean).join('~'); }
|
|
207
|
+
|
|
184
208
|
const tmpStanzas = [];
|
|
185
209
|
if (tmpBaseFilter) { tmpStanzas.push(tmpBaseFilter); }
|
|
186
210
|
if (pSearchTerm) { tmpStanzas.push(this.buildSearchFilter(tmpSearchFields, pSearchTerm)); }
|
|
@@ -324,6 +324,65 @@ class PictViewPicker extends libPictView
|
|
|
324
324
|
}
|
|
325
325
|
}
|
|
326
326
|
|
|
327
|
+
/**
|
|
328
|
+
* Public: set the picker's value programmatically (e.g. when a host form marshals data into it).
|
|
329
|
+
* Accepts a scalar (single mode) or an array / csv string (multi mode), seeds display text for any
|
|
330
|
+
* unknown values (from the source rows, else async ResolveValue), then repaints.
|
|
331
|
+
* @param {any} pValue
|
|
332
|
+
* @return {PictViewPicker} this
|
|
333
|
+
*/
|
|
334
|
+
setValue(pValue)
|
|
335
|
+
{
|
|
336
|
+
if (this._isMulti())
|
|
337
|
+
{
|
|
338
|
+
let tmpArray = pValue;
|
|
339
|
+
if (tmpArray === undefined || tmpArray === null || tmpArray === '') { tmpArray = []; }
|
|
340
|
+
else if (typeof tmpArray === 'string') { tmpArray = tmpArray.split(',').filter((pPart) => pPart !== ''); }
|
|
341
|
+
else if (!Array.isArray(tmpArray)) { tmpArray = [ tmpArray ]; }
|
|
342
|
+
this._setValue(tmpArray);
|
|
343
|
+
this._seedSelectedRecords(tmpArray);
|
|
344
|
+
}
|
|
345
|
+
else
|
|
346
|
+
{
|
|
347
|
+
this._setValue(pValue);
|
|
348
|
+
this._selectedText = null;
|
|
349
|
+
this._seedSelectedRecords((pValue === undefined || pValue === null || pValue === '') ? [] : [ pValue ]);
|
|
350
|
+
}
|
|
351
|
+
this.render();
|
|
352
|
+
return this;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Ensure each value has a {Value,Text} in _selectedRecords — from the current source rows when
|
|
357
|
+
* present, else (async mode) fetched via ResolveValue and painted in when it resolves.
|
|
358
|
+
* @param {Array<any>} pValues
|
|
359
|
+
*/
|
|
360
|
+
_seedSelectedRecords(pValues)
|
|
361
|
+
{
|
|
362
|
+
pValues.forEach((pVal) =>
|
|
363
|
+
{
|
|
364
|
+
if (pVal === undefined || pVal === null || pVal === '' || this._selectedRecords[String(pVal)]) { return; }
|
|
365
|
+
const tmpRow = this._sourceRows().find((pRow) => String(pRow.Value) === String(pVal));
|
|
366
|
+
if (tmpRow)
|
|
367
|
+
{
|
|
368
|
+
this._selectedRecords[String(pVal)] = { Value: tmpRow.Value, Text: tmpRow.Text };
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
if (this._isAsync() && typeof this.options.ResolveValue === 'function')
|
|
372
|
+
{
|
|
373
|
+
Promise.resolve(this.options.ResolveValue(pVal)).then((pResolved) =>
|
|
374
|
+
{
|
|
375
|
+
if (pResolved && pResolved.Text)
|
|
376
|
+
{
|
|
377
|
+
this._selectedRecords[String(pVal)] = { Value: pResolved.Value !== undefined ? pResolved.Value : pVal, Text: pResolved.Text };
|
|
378
|
+
if (!this._isMulti()) { this._selectedText = pResolved.Text; }
|
|
379
|
+
this._renderValue();
|
|
380
|
+
}
|
|
381
|
+
}).catch(() => { /* leave the raw value showing */ });
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
|
|
327
386
|
/** @return {Array<{Value:any, Text:string}>} The current option source rows (async results or static Options). */
|
|
328
387
|
_sourceRows()
|
|
329
388
|
{
|
|
@@ -516,11 +575,51 @@ class PictViewPicker extends libPictView
|
|
|
516
575
|
this._open = true;
|
|
517
576
|
this._highlight = -1;
|
|
518
577
|
this._paintOpen();
|
|
578
|
+
this._positionPop();
|
|
519
579
|
if (this._isAsync() && !this._loaded) { this._loadPage(0, false); }
|
|
520
580
|
const tmpSearch = /** @type {HTMLInputElement} */ (document.getElementById(`PPS_Search_${this.options.PickerHash}`));
|
|
521
581
|
if (tmpSearch) { tmpSearch.focus(); tmpSearch.select(); }
|
|
522
582
|
}
|
|
523
583
|
|
|
584
|
+
/**
|
|
585
|
+
* Position the (fixed) dropdown against the control, flipping above when there's more room there.
|
|
586
|
+
* Because the popover is position:fixed (viewport-anchored), no ancestor overflow can clip it; the
|
|
587
|
+
* trade-off is we set its top/left/width ourselves from the control's rect on open.
|
|
588
|
+
*/
|
|
589
|
+
_positionPop()
|
|
590
|
+
{
|
|
591
|
+
const tmpRoot = document.getElementById(`PPS_${this.options.PickerHash}`);
|
|
592
|
+
if (!tmpRoot) { return; }
|
|
593
|
+
const tmpControl = tmpRoot.querySelector('.pps-control');
|
|
594
|
+
const tmpPop = /** @type {HTMLElement} */ (tmpRoot.querySelector('.pps-pop'));
|
|
595
|
+
const tmpPanel = /** @type {HTMLElement} */ (tmpRoot.querySelector('.pps-panel'));
|
|
596
|
+
if (!tmpControl || !tmpPop) { return; }
|
|
597
|
+
const tmpRect = tmpControl.getBoundingClientRect();
|
|
598
|
+
const tmpGap = 5;
|
|
599
|
+
const tmpMargin = 8;
|
|
600
|
+
const tmpVH = window.innerHeight;
|
|
601
|
+
const tmpVW = window.innerWidth;
|
|
602
|
+
const tmpWidth = Math.max(200, Math.round(tmpRect.width));
|
|
603
|
+
tmpPop.style.width = `${tmpWidth}px`;
|
|
604
|
+
tmpPop.style.left = `${Math.round(Math.max(tmpMargin, Math.min(tmpRect.left, tmpVW - tmpWidth - tmpMargin)))}px`;
|
|
605
|
+
tmpPop.style.right = 'auto';
|
|
606
|
+
const tmpSpaceBelow = tmpVH - tmpRect.bottom - tmpGap - tmpMargin;
|
|
607
|
+
const tmpSpaceAbove = tmpRect.top - tmpGap - tmpMargin;
|
|
608
|
+
// Prefer the natural downward direction; only flip above when the room below is genuinely cramped.
|
|
609
|
+
if (tmpSpaceBelow >= 200 || tmpSpaceBelow >= tmpSpaceAbove)
|
|
610
|
+
{
|
|
611
|
+
tmpPop.style.top = `${Math.round(tmpRect.bottom + tmpGap)}px`;
|
|
612
|
+
tmpPop.style.bottom = 'auto';
|
|
613
|
+
if (tmpPanel) { tmpPanel.style.maxHeight = `${Math.max(140, Math.min(tmpSpaceBelow, 360))}px`; }
|
|
614
|
+
}
|
|
615
|
+
else
|
|
616
|
+
{
|
|
617
|
+
tmpPop.style.top = 'auto';
|
|
618
|
+
tmpPop.style.bottom = `${Math.round(tmpVH - tmpRect.top + tmpGap)}px`;
|
|
619
|
+
if (tmpPanel) { tmpPanel.style.maxHeight = `${Math.max(140, Math.min(tmpSpaceAbove, 360))}px`; }
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
|
|
524
623
|
/** Async mode: load + append the next page of results. */
|
|
525
624
|
loadMore()
|
|
526
625
|
{
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export = PictInputTypePicker;
|
|
2
|
+
declare const PictInputTypePicker_base: typeof import("pict-section-form/types/source/providers/Pict-Provider-InputExtension");
|
|
3
|
+
declare class PictInputTypePicker extends PictInputTypePicker_base {
|
|
4
|
+
constructor(pFable: any, pOptions: any, pServiceHash: any);
|
|
5
|
+
getPickerHostID(pRawHTMLID: any): string;
|
|
6
|
+
getPickerHash(pRawHTMLID: any): string;
|
|
7
|
+
getTabularPickerHostID(pRawHTMLID: any, pRowIndex: any): string;
|
|
8
|
+
getTabularPickerHash(pRawHTMLID: any, pRowIndex: any): string;
|
|
9
|
+
getTabularHiddenID(pRawHTMLID: any, pRowIndex: any): string;
|
|
10
|
+
/**
|
|
11
|
+
* Overridable: extra FoxHound scope stanza(s) AND-applied to the entity search. Default reads the
|
|
12
|
+
* descriptor's `GetContextScopeFilter()` hook (set by the host / recordset filter base), else its
|
|
13
|
+
* static `BaseFilter`. Host subclasses override this to read app state (project / spec-year / …).
|
|
14
|
+
*
|
|
15
|
+
* @param {Record<string, any>} pInput @return {string|Array<string>}
|
|
16
|
+
*/
|
|
17
|
+
getContextualSearchFilters(pInput: Record<string, any>): string | Array<string>;
|
|
18
|
+
/** Build the picker config from a form input descriptor. */
|
|
19
|
+
_buildPickerConfig(pInput: any, pHostSelector: any, fOnChange: any): {
|
|
20
|
+
DestinationAddress: any;
|
|
21
|
+
Mode: string;
|
|
22
|
+
Placeholder: any;
|
|
23
|
+
Searchable: boolean;
|
|
24
|
+
Entity: any;
|
|
25
|
+
SearchFields: any;
|
|
26
|
+
ValueField: any;
|
|
27
|
+
TextField: any;
|
|
28
|
+
PageSize: any;
|
|
29
|
+
Options: any;
|
|
30
|
+
BaseFilter: () => string | string[];
|
|
31
|
+
OnChange: any;
|
|
32
|
+
};
|
|
33
|
+
/** Instantiate (or reuse) the picker view for a config — entity-backed when Entity is set. */
|
|
34
|
+
_instantiatePicker(pPickerHash: any, pConfig: any): any;
|
|
35
|
+
/**
|
|
36
|
+
* Write a picker value into the form: csv to the hidden informary input (+ dataChanged), plus the
|
|
37
|
+
* raw array to `PictForm.ValueArrayAddress` when set (the recordset filter reads Values as an
|
|
38
|
+
* array). The csv-vs-array bridge lives HERE (generic) instead of in each host.
|
|
39
|
+
*/
|
|
40
|
+
_commit(pView: any, pInput: any, pValue: any, pHTMLSelector: any): void;
|
|
41
|
+
_commitTabular(pView: any, pInput: any, pValue: any, pHiddenID: any, pRowIndex: any): void;
|
|
42
|
+
/**
|
|
43
|
+
* Idempotently mount (or reuse) the picker into its host element + seed its value. Called from both
|
|
44
|
+
* onInputInitialize and onDataMarshalToForm because, in the async-virtual filter render, the host
|
|
45
|
+
* element only exists in the real DOM by the marshal pass — whichever hook fires post-DOM wins, and
|
|
46
|
+
* re-calls are harmless (the picker view is reused by hash).
|
|
47
|
+
* @return {boolean} true if the picker is mounted.
|
|
48
|
+
*/
|
|
49
|
+
_mountPicker(pView: any, pInput: any, pValue: any, pHostSelector: any, pPickerHash: any, fOnChange: any): boolean;
|
|
50
|
+
onInputInitialize(pView: any, pGroup: any, pRow: any, pInput: any, pValue: any, pHTMLSelector: any, pTransactionGUID: any): boolean;
|
|
51
|
+
onDataMarshalToForm(pView: any, pGroup: any, pRow: any, pInput: any, pValue: any, pHTMLSelector: any, pTransactionGUID: any): boolean;
|
|
52
|
+
onDataRequest(pView: any, pInput: any, pValue: any, pHTMLSelector: any): boolean;
|
|
53
|
+
/** Idempotent tabular mount (see _mountPicker). @return {boolean} */
|
|
54
|
+
_mountPickerTabular(pView: any, pInput: any, pValue: any, pRowIndex: any): boolean;
|
|
55
|
+
onInputInitializeTabular(pView: any, pGroup: any, pInput: any, pValue: any, pHTMLSelector: any, pRowIndex: any, pTransactionGUID: any): boolean;
|
|
56
|
+
onDataMarshalToFormTabular(pView: any, pGroup: any, pInput: any, pValue: any, pHTMLSelector: any, pRowIndex: any, pTransactionGUID: any): boolean;
|
|
57
|
+
onDataRequestTabular(pView: any, pInput: any, pValue: any, pHTMLSelector: any, pRowIndex: any): boolean;
|
|
58
|
+
}
|
|
59
|
+
declare namespace PictInputTypePicker {
|
|
60
|
+
export { PictInputTypePicker, registerPickerInputType, buildPickerInputTemplates, _DEFAULT_CONFIGURATION as default_configuration };
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Register the Picker InputType on a pict instance: the input-extension provider + its metatemplate(s).
|
|
64
|
+
* Idempotent. Requires `pict-section-form` loaded (PictFormSectionDefaultTemplateProvider present) and
|
|
65
|
+
* the `Pict-Section-Picker` provider registered.
|
|
66
|
+
*
|
|
67
|
+
* @param {any} pPict - the pict instance.
|
|
68
|
+
* @param {Record<string, any>} [pOptions]
|
|
69
|
+
* - InputTypeName {string} - the InputType string (default 'Picker').
|
|
70
|
+
* - ProviderHash {string} - the input-extension provider service hash (default 'Pict-Input-Picker').
|
|
71
|
+
* - ProviderClass {Function} - provider class to register (default PictInputTypePicker; a host
|
|
72
|
+
* passes a subclass that overrides getContextualSearchFilters for its scoping).
|
|
73
|
+
* - TemplatePrefix {string|Array<string>} - the form template prefix(es) to inject the metatemplate
|
|
74
|
+
* under (default 'Pict-MT-Base'; Headlight uses its theme prefixes).
|
|
75
|
+
* @return {boolean} true if registered.
|
|
76
|
+
*/
|
|
77
|
+
declare function registerPickerInputType(pPict: any, pOptions?: Record<string, any>): boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Build the InputType metatemplate entries (a hidden informary input + a host element the picker
|
|
80
|
+
* renders into) for a given InputType name + provider hash. Injected via injectTemplateSet.
|
|
81
|
+
*
|
|
82
|
+
* @param {string} pInputTypeName - e.g. 'Picker'.
|
|
83
|
+
* @param {string} pProviderHash - the input-extension provider service hash to auto-attach.
|
|
84
|
+
* @return {Array<Record<string, any>>}
|
|
85
|
+
*/
|
|
86
|
+
declare function buildPickerInputTemplates(pInputTypeName: string, pProviderHash: string): Array<Record<string, any>>;
|
|
87
|
+
/** @type {Record<string, any>} */
|
|
88
|
+
declare const _DEFAULT_CONFIGURATION: Record<string, any>;
|
|
89
|
+
//# sourceMappingURL=Pict-Section-Picker-FormInput.d.ts.map
|
|
@@ -0,0 +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;;;;;;;;;;;;;MAkBC;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;AAzQD;;;;;;;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"}
|
|
@@ -46,7 +46,10 @@ declare class PictProviderPicker extends libPictProvider {
|
|
|
46
46
|
* - TextField {string} - record field used as the option Text (default `Name`).
|
|
47
47
|
* - PageSize {number} - records per page (default 20).
|
|
48
48
|
* - Sort {string} - optional field to sort ascending (adds `FSF~<field>~ASC~0`).
|
|
49
|
-
* - BaseFilter {string} - optional always-applied FoxHound filter (AND),
|
|
49
|
+
* - BaseFilter {string|Array<string>|function} - optional always-applied FoxHound filter (AND),
|
|
50
|
+
* e.g. `FBV~IDCustomer~EQ~1`. May be a **function** `(searchTerm, page) => string|string[]`
|
|
51
|
+
* evaluated on every search — the generic hook for host-injected CONTEXTUAL scoping (project,
|
|
52
|
+
* tenant, spec-year, …). The module stays agnostic; the host supplies the closure.
|
|
50
53
|
* - MapRecord {function} - optional `(record) => {Value, Text}` mapper (overrides Value/TextField).
|
|
51
54
|
* @return {(pSearchTerm: string, pPage: number) => Promise<{results: Array<any>, hasMore: boolean}>}
|
|
52
55
|
*/
|
|
@@ -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":";AAmFA;;;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;;;;;;;;;;;;;;;;;;OAkBG;IACH,kCAdW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAYlB,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,CAkDnG;IAED;;;;;;OAMG;IACH,kCAHW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAClB,CAAC,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAsBxC;IAED;;;;;;;;;OASG;IACH,gCAJW,MAAM,WACN,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAClB,GAAG,CAQd;CACD;;;;;AAxMD,kCAAkC;AAClC,sCADW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAO5B"}
|
|
@@ -34,6 +34,20 @@ declare class PictViewPicker extends libPictView {
|
|
|
34
34
|
*/
|
|
35
35
|
_setValue(pValue: any): void;
|
|
36
36
|
_value: any;
|
|
37
|
+
/**
|
|
38
|
+
* Public: set the picker's value programmatically (e.g. when a host form marshals data into it).
|
|
39
|
+
* Accepts a scalar (single mode) or an array / csv string (multi mode), seeds display text for any
|
|
40
|
+
* unknown values (from the source rows, else async ResolveValue), then repaints.
|
|
41
|
+
* @param {any} pValue
|
|
42
|
+
* @return {PictViewPicker} this
|
|
43
|
+
*/
|
|
44
|
+
setValue(pValue: any): PictViewPicker;
|
|
45
|
+
/**
|
|
46
|
+
* Ensure each value has a {Value,Text} in _selectedRecords — from the current source rows when
|
|
47
|
+
* present, else (async mode) fetched via ResolveValue and painted in when it resolves.
|
|
48
|
+
* @param {Array<any>} pValues
|
|
49
|
+
*/
|
|
50
|
+
_seedSelectedRecords(pValues: Array<any>): void;
|
|
37
51
|
/** @return {Array<{Value:any, Text:string}>} The current option source rows (async results or static Options). */
|
|
38
52
|
_sourceRows(): Array<{
|
|
39
53
|
Value: any;
|
|
@@ -66,6 +80,12 @@ declare class PictViewPicker extends libPictView {
|
|
|
66
80
|
onControlKey(pEvent: any): void;
|
|
67
81
|
/** Open the dropdown and focus the search box. */
|
|
68
82
|
open(): void;
|
|
83
|
+
/**
|
|
84
|
+
* Position the (fixed) dropdown against the control, flipping above when there's more room there.
|
|
85
|
+
* Because the popover is position:fixed (viewport-anchored), no ancestor overflow can clip it; the
|
|
86
|
+
* trade-off is we set its top/left/width ourselves from the control's rect on open.
|
|
87
|
+
*/
|
|
88
|
+
_positionPop(): void;
|
|
69
89
|
/** Async mode: load + append the next page of results. */
|
|
70
90
|
loadMore(): void;
|
|
71
91
|
/** Close the dropdown. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PictView-Picker.d.ts","sourceRoot":"","sources":["../../source/views/PictView-Picker.js"],"names":[],"mappings":";AA6KA;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,kHAAkH;IAClH,eADa,KAAK,CAAC;QAAC,KAAK,EAAC,GAAG,CAAC;QAAC,IAAI,EAAC,MAAM,CAAA;KAAC,CAAC,CAK3C;IAED;;;OAGG;IACH,mCAgGC;IAED;;;;;OAKG;IACH,sBAHW,GAAG,GACF;QAAC,KAAK,EAAC,GAAG,CAAC;QAAC,IAAI,EAAC,MAAM,CAAA;KAAC,GAAC,IAAI,CAQxC;IAED;;;;OAIG;IACH,iBAHW,MAAM,WACN,OAAO,QA4BjB;IAWD,uCAAuC;IACvC,0BAIC;IAED,+EAA+E;IAC/E,gCAWC;IAED,kDAAkD;IAClD,
|
|
1
|
+
{"version":3,"file":"PictView-Picker.d.ts","sourceRoot":"","sources":["../../source/views/PictView-Picker.js"],"names":[],"mappings":";AA6KA;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,kHAAkH;IAClH,eADa,KAAK,CAAC;QAAC,KAAK,EAAC,GAAG,CAAC;QAAC,IAAI,EAAC,MAAM,CAAA;KAAC,CAAC,CAK3C;IAED;;;OAGG;IACH,mCAgGC;IAED;;;;;OAKG;IACH,sBAHW,GAAG,GACF;QAAC,KAAK,EAAC,GAAG,CAAC;QAAC,IAAI,EAAC,MAAM,CAAA;KAAC,GAAC,IAAI,CAQxC;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,QA4ChB;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;;;;;AA30BD,kCAAkC;AAClC,sCADW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAyK5B"}
|