pict-section-recordset 1.3.1 → 1.5.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/package.json +1 -1
- package/source/views/Filter-PersistenceView.js +4 -0
- package/source/views/RecordSet-Filters.js +44 -3
- package/source/views/filters/RecordSet-Filter-EntityReference-Base.js +304 -0
- package/source/views/filters/RecordSet-Filter-ExternalJoinSelectedValue.js +10 -256
- package/source/views/filters/RecordSet-Filter-ExternalJoinSelectedValueList.js +10 -263
- package/source/views/filters/RecordSet-Filter-InternalJoinSelectedValue.js +10 -256
- package/source/views/filters/RecordSet-Filter-InternalJoinSelectedValueList.js +10 -263
- package/types/views/Filter-PersistenceView.d.ts.map +1 -1
- package/types/views/RecordSet-Filters.d.ts +8 -0
- package/types/views/RecordSet-Filters.d.ts.map +1 -1
- package/types/views/filters/RecordSet-Filter-EntityReference-Base.d.ts +37 -0
- package/types/views/filters/RecordSet-Filter-EntityReference-Base.d.ts.map +1 -0
- package/types/views/filters/RecordSet-Filter-ExternalJoinSelectedValue.d.ts +13 -18
- package/types/views/filters/RecordSet-Filter-ExternalJoinSelectedValue.d.ts.map +1 -1
- package/types/views/filters/RecordSet-Filter-ExternalJoinSelectedValueList.d.ts +13 -18
- package/types/views/filters/RecordSet-Filter-ExternalJoinSelectedValueList.d.ts.map +1 -1
- package/types/views/filters/RecordSet-Filter-InternalJoinSelectedValue.d.ts +13 -18
- package/types/views/filters/RecordSet-Filter-InternalJoinSelectedValue.d.ts.map +1 -1
- package/types/views/filters/RecordSet-Filter-InternalJoinSelectedValueList.d.ts +13 -18
- package/types/views/filters/RecordSet-Filter-InternalJoinSelectedValueList.d.ts.map +1 -1
package/package.json
CHANGED
|
@@ -29,6 +29,10 @@ const _DEFAULT_CONFIGURATION_FilterPersistenceView = (
|
|
|
29
29
|
.prsp-exp-select, .prsp-exp-name { font: inherit; font-size: 0.9rem; padding: 0.42rem 0.6rem; border-radius: 8px;
|
|
30
30
|
border: 1px solid var(--theme-color-border-default, #d7dce3); background: var(--theme-color-background-primary, #fff); color: var(--theme-color-text-primary, #1f2733); }
|
|
31
31
|
.prsp-exp-select { flex: 0 0 auto; width: 230px; min-width: 0; max-width: 100%; }
|
|
32
|
+
/* When a host layers select2 (or a similar widget) on the stored-filter <select>, its container
|
|
33
|
+
defaults to display:block at the row's full width, pushing Save/Delete onto a second line. Pin it to
|
|
34
|
+
a fixed-width inline flex item so the controls stay on one row. */
|
|
35
|
+
.prsp-exp-row .select2-container { flex: 0 0 auto !important; display: inline-block !important; width: 230px !important; max-width: 100%; vertical-align: middle; }
|
|
32
36
|
.prsp-exp-select:focus, .prsp-exp-name:focus { outline: none; border-color: var(--theme-color-brand-primary, #156dd1);
|
|
33
37
|
box-shadow: 0 0 0 3px color-mix(in srgb, var(--theme-color-brand-primary, #156dd1) 16%, transparent); }
|
|
34
38
|
.prsp-exp-btn { flex: 0 0 auto; white-space: nowrap; }
|
|
@@ -67,7 +67,9 @@ const _DEFAULT_CONFIGURATION_SUBSET_Filter =
|
|
|
67
67
|
.prsp-filters-actions { flex: 0 0 auto; display: flex; align-items: center; gap: 0.5rem; }
|
|
68
68
|
|
|
69
69
|
/* Module-owned "Add filter" popover (replaces the old native <select> pickers). */
|
|
70
|
-
|
|
70
|
+
/* Fixed (viewport-anchored) + JS-positioned on open, so no ancestor overflow:hidden — the filter card,
|
|
71
|
+
the slide-out drawer — can clip it, whatever the host's layout. */
|
|
72
|
+
.prsp-addfilter-pop { position: fixed; z-index: 30; min-width: 280px; max-width: 360px; display: none; }
|
|
71
73
|
.prsp-addfilter-pop.open { display: block; }
|
|
72
74
|
/* Transparent full-viewport backdrop: catches outside clicks to close (no document listener). */
|
|
73
75
|
.prsp-addfilter-backdrop { position: fixed; inset: 0; z-index: 0; }
|
|
@@ -112,7 +114,7 @@ const _DEFAULT_CONFIGURATION_SUBSET_Filter =
|
|
|
112
114
|
</form>
|
|
113
115
|
<div class="prsp-filters-drawer" id="PRSP_Filter_Drawer">
|
|
114
116
|
<div class="prsp-filters-drawer-inner">
|
|
115
|
-
<div id="PRSP_Filter_Instances" class="prsp-filters-clauses">
|
|
117
|
+
<div id="PRSP_Filter_Instances" class="prsp-filters-clauses" onkeydown="if (event.key === 'Enter' && !event.target.closest('.pps')) { event.preventDefault(); _Pict.views['PRSP-Filters'].handleSearch(event, '{~D:Record.RecordSet~}', '{~D:Record.ViewContext~}'); }">
|
|
116
118
|
{~FIV:Record~}
|
|
117
119
|
</div>
|
|
118
120
|
{~T:PRSP-SUBSET-Filters-Template-AddFilter-Fieldset~}
|
|
@@ -751,7 +753,46 @@ class ViewRecordSetSUBSETFilters extends libPictView
|
|
|
751
753
|
_paintAddFilterOpenState()
|
|
752
754
|
{
|
|
753
755
|
const tmpPopover = document.getElementById('PRSP_AddFilter_Popover');
|
|
754
|
-
if (tmpPopover) {
|
|
756
|
+
if (!tmpPopover) { return; }
|
|
757
|
+
tmpPopover.classList.toggle('open', !!this._addFilterOpen);
|
|
758
|
+
if (this._addFilterOpen) { this._positionAddFilterPopover(tmpPopover); }
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
/**
|
|
762
|
+
* Position the (fixed) add-filter popover against its trigger button, flipping above when there's
|
|
763
|
+
* more room there. Fixed positioning means no ancestor overflow:hidden (the host's filter card, the
|
|
764
|
+
* slide-out drawer) can clip it — the price is we set its top/left from the trigger's rect here.
|
|
765
|
+
*
|
|
766
|
+
* @param {HTMLElement} pPopover - the #PRSP_AddFilter_Popover element (already display:block).
|
|
767
|
+
*/
|
|
768
|
+
_positionAddFilterPopover(pPopover)
|
|
769
|
+
{
|
|
770
|
+
const tmpTrigger = document.getElementById('PRSP_Filter_Button_Add');
|
|
771
|
+
if (!tmpTrigger) { return; }
|
|
772
|
+
const tmpPanel = /** @type {HTMLElement} */ (pPopover.querySelector('.prsp-addfilter-panel'));
|
|
773
|
+
const tmpRect = tmpTrigger.getBoundingClientRect();
|
|
774
|
+
const tmpGap = 6;
|
|
775
|
+
const tmpMargin = 8;
|
|
776
|
+
const tmpVH = window.innerHeight;
|
|
777
|
+
const tmpVW = window.innerWidth;
|
|
778
|
+
const tmpWidth = pPopover.offsetWidth || 300;
|
|
779
|
+
pPopover.style.left = `${Math.round(Math.max(tmpMargin, Math.min(tmpRect.left, tmpVW - tmpWidth - tmpMargin)))}px`;
|
|
780
|
+
pPopover.style.right = 'auto';
|
|
781
|
+
const tmpSpaceBelow = tmpVH - tmpRect.bottom - tmpGap - tmpMargin;
|
|
782
|
+
const tmpSpaceAbove = tmpRect.top - tmpGap - tmpMargin;
|
|
783
|
+
// Prefer the natural downward direction; only flip above when the room below is genuinely cramped.
|
|
784
|
+
if (tmpSpaceBelow >= 220 || tmpSpaceBelow >= tmpSpaceAbove)
|
|
785
|
+
{
|
|
786
|
+
pPopover.style.top = `${Math.round(tmpRect.bottom + tmpGap)}px`;
|
|
787
|
+
pPopover.style.bottom = 'auto';
|
|
788
|
+
if (tmpPanel) { tmpPanel.style.maxHeight = `${Math.max(160, Math.min(tmpSpaceBelow, 460))}px`; }
|
|
789
|
+
}
|
|
790
|
+
else
|
|
791
|
+
{
|
|
792
|
+
pPopover.style.top = 'auto';
|
|
793
|
+
pPopover.style.bottom = `${Math.round(tmpVH - tmpRect.top + tmpGap)}px`;
|
|
794
|
+
if (tmpPanel) { tmpPanel.style.maxHeight = `${Math.max(160, Math.min(tmpSpaceAbove, 460))}px`; }
|
|
795
|
+
}
|
|
755
796
|
}
|
|
756
797
|
|
|
757
798
|
/**
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
const ViewRecordSetSUBSETFilterBase = require('./RecordSet-Filter-Base');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Shared base for the four entity-reference filter types — Internal/External join × single/list.
|
|
5
|
+
*
|
|
6
|
+
* These were ~95% duplicate views, each with the same bespoke "search results | selection" table UI
|
|
7
|
+
* and identical search/add/remove logic. This base consolidates all of it. Subclasses supply only the
|
|
8
|
+
* two seams that actually differ:
|
|
9
|
+
* - `getSearchEntity(pClause)` — internal join searches `RemoteTable`, external `ExternalFilterByTable`.
|
|
10
|
+
* - `isMultiSelect()` — the `…List` variants append; the plain `…SelectedValue` variants replace.
|
|
11
|
+
*
|
|
12
|
+
* Rendering uses the same mechanism as before (the input template is emitted during the clause's
|
|
13
|
+
* template parse, via `getFilterFormTemplate()`), so the consolidation is behavior-preserving. The
|
|
14
|
+
* input template is itself a seam (`getEntityInputTemplate()`) so a host can swap the table UI for a
|
|
15
|
+
* picker-backed input (a pict-section-form `Picker` InputType) without the module changing.
|
|
16
|
+
*
|
|
17
|
+
* Host-injected contextual scoping rides through `getContextScopeFilter(pClause)` — extra FoxHound
|
|
18
|
+
* stanzas AND-applied to the entity search (project / spec-year / …). The module never learns what
|
|
19
|
+
* those contexts mean; the host overrides the hook to read its own app state.
|
|
20
|
+
*/
|
|
21
|
+
const _DEFAULT_CONFIGURATION_EntityReference =
|
|
22
|
+
{
|
|
23
|
+
ViewIdentifier: 'PRSP-FilterType-EntityReference-Base',
|
|
24
|
+
|
|
25
|
+
// When set (by a host), entity clauses delegate their input to this pict-section-form InputType
|
|
26
|
+
// (rendered via {~IWVDA:PSRSFilterProxyView:Record.ClauseDescriptor~}) instead of the built-in
|
|
27
|
+
// table UI — e.g. 'Picker' to use pict-section-picker. Default false → the table UI.
|
|
28
|
+
EntityInputType: false,
|
|
29
|
+
|
|
30
|
+
Templates:
|
|
31
|
+
[
|
|
32
|
+
{
|
|
33
|
+
// Table UI (default). Two cells: live search results | current selection.
|
|
34
|
+
Hash: 'PRSP-Filter-EntityRef-Table',
|
|
35
|
+
Template: /*html*/`
|
|
36
|
+
<table><tbody><tr>
|
|
37
|
+
<td valign="top">{~T:PRSP-Filter-EntityRef-SearchResults~}</td>
|
|
38
|
+
<td valign="top">{~T:PRSP-Filter-EntityRef-SelectedValues~}</td>
|
|
39
|
+
</tr></tbody></table>
|
|
40
|
+
`
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
// Picker / form-input delegation (opt-in via EntityInputType). Renders one dynamic input
|
|
44
|
+
// on the shared PSRSFilterProxyView from the clause's ClauseDescriptor (whose PictForm
|
|
45
|
+
// InputType is stamped in prepareRecord). Bound to the clause's Values address.
|
|
46
|
+
Hash: 'PRSP-Filter-EntityRef-Input',
|
|
47
|
+
Template: /*html*/`
|
|
48
|
+
{~IWVDA:PSRSFilterProxyView:Record.ClauseDescriptor~}
|
|
49
|
+
`
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
Hash: 'PRSP-Filter-EntityRef-SearchResults',
|
|
53
|
+
Template: /*html*/`
|
|
54
|
+
<form id="PRSP_Filter_{~D:Record.Hash~}_Search_Form" onsubmit="_Pict.views['{~D:Context[0].Hash~}'].performSearch(event, '{~D:Record.ClauseAddress~}', '{~D:Record.Hash~}'); return false;">
|
|
55
|
+
<input id="PRSP_Filter_{~D:Record.Hash~}_Search_Value" type="text" placeholder="Search..." value="{~D:Record.SearchInputValue~}" />
|
|
56
|
+
<button type="submit" id="PRSP_Filter_{~D:Record.Hash~}_Button_Search" onclick="_Pict.views['{~D:Context[0].Hash~}'].performSearch(event, '{~D:Record.ClauseAddress~}', '{~D:Record.Hash~}')">Search</button>
|
|
57
|
+
</form>
|
|
58
|
+
<table>
|
|
59
|
+
<thead><tr><th colspan="2">{~D:Record.Label~}</th></tr></thead>
|
|
60
|
+
<tbody>{~TSWP:PRSP-Filter-EntityRef-SearchResults-Entry:Record.SearchResults:Record~}</tbody>
|
|
61
|
+
</table>
|
|
62
|
+
<button type="button" id="PRSP_Filter_{~D:Record.Hash~}_Button_LoadMore" class="is-hidden" onclick="_Pict.views['{~D:Context[0].Hash~}'].loadMore(event, '{~D:Record.ClauseAddress~}', '{~D:Record.Hash~}', {~D:Record.SearchResultsOffset:0~})">Load More</button>
|
|
63
|
+
`
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
Hash: 'PRSP-Filter-EntityRef-SelectedValues',
|
|
67
|
+
Template: /*html*/`
|
|
68
|
+
<table>
|
|
69
|
+
<thead><tr><th colspan="2">Selection</th></tr></thead>
|
|
70
|
+
<tbody>{~TSWP:PRSP-Filter-EntityRef-SelectedValues-Entry:Record.SelectedValues:Record~}</tbody>
|
|
71
|
+
</table>
|
|
72
|
+
`
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
Hash: 'PRSP-Filter-EntityRef-SearchResults-Entry',
|
|
76
|
+
Template: /*html*/`
|
|
77
|
+
<tr><td><button onclick="_Pict.views['{~D:Context[0].Hash~}'].handleAdd(event, {~DVBK:Record.Data:Record.Payload.ExternalFilterTableLookupColumn~}, '{~D:Record.Payload.ClauseAddress~}', '{~D:Record.Payload.Hash~}')">Select</button></td><td>{~TFA:Record.Payload.ExternalRecordDisplayTemplate:Record~}</td></tr>
|
|
78
|
+
`
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
Hash: 'PRSP-Filter-EntityRef-SelectedValues-Entry',
|
|
82
|
+
Template: /*html*/`
|
|
83
|
+
<tr><td><button onclick="_Pict.views['{~D:Context[0].Hash~}'].handleRemove(event, {~DVBK:Record.Data:Record.Payload.ExternalFilterTableLookupColumn~}, '{~D:Record.Payload.ClauseAddress~}', '{~D:Record.Payload.Hash~}')">Remove</button></td><td>{~TFA:Record.Payload.ExternalRecordDisplayTemplate:Record~}</td></tr>
|
|
84
|
+
`
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
class ViewRecordSetSUBSETFilterEntityReferenceBase extends ViewRecordSetSUBSETFilterBase
|
|
90
|
+
{
|
|
91
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
92
|
+
{
|
|
93
|
+
if (!pOptions.PageSize)
|
|
94
|
+
{
|
|
95
|
+
pOptions.PageSize = 15;
|
|
96
|
+
}
|
|
97
|
+
super(pFable, pOptions, pServiceHash);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// --- Seams the subclasses override (the only real differences between the 4 types) ---
|
|
101
|
+
|
|
102
|
+
/** @param {Record<string, any>} pClause @return {string} The entity to search (RemoteTable / ExternalFilterByTable). */
|
|
103
|
+
getSearchEntity(pClause)
|
|
104
|
+
{
|
|
105
|
+
return pClause.RemoteTable || pClause.ExternalFilterByTable;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** @param {Record<string, any>} pClause @return {string} The value/ID column on the searched entity. */
|
|
109
|
+
getLookupColumn(pClause)
|
|
110
|
+
{
|
|
111
|
+
return pClause.ExternalFilterTableLookupColumn || `ID${this.getSearchEntity(pClause)}`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** @return {boolean} True for the `…List` (multi-select) variants. */
|
|
115
|
+
isMultiSelect()
|
|
116
|
+
{
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Host-injectable contextual search scope. Returns extra FoxHound filter stanza(s) AND-applied to
|
|
122
|
+
* the entity search (e.g. "only this project's line items"). Default: the clause's static
|
|
123
|
+
* `ContextScopeFilter` if any, else none. Hosts override this to read app state — the module never
|
|
124
|
+
* learns what a "project" or "spec year" is.
|
|
125
|
+
*
|
|
126
|
+
* @param {Record<string, any>} pClause @return {string|Array<string>}
|
|
127
|
+
*/
|
|
128
|
+
getContextScopeFilter(pClause)
|
|
129
|
+
{
|
|
130
|
+
return pClause.ContextScopeFilter || '';
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** @return {string} The template hash for the clause's value input (table UI, or the opt-in delegated input). */
|
|
134
|
+
getFilterFormTemplate()
|
|
135
|
+
{
|
|
136
|
+
return this.options.EntityInputType ? 'PRSP-Filter-EntityRef-Input' : 'PRSP-Filter-EntityRef-Table';
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** @param {Record<string, any>} pRecord */
|
|
140
|
+
prepareRecord(pRecord)
|
|
141
|
+
{
|
|
142
|
+
super.prepareRecord(pRecord);
|
|
143
|
+
|
|
144
|
+
pRecord.ClauseDescriptor.PictForm = Object.assign({}, pRecord.PictForm);
|
|
145
|
+
if (this.options.EntityInputType)
|
|
146
|
+
{
|
|
147
|
+
// Delegated input: a csv string round-trips through the informary at `.StringArrayValue`,
|
|
148
|
+
// while the picker adapter writes the real ARRAY to `.Values` (what Filter.js reads) via
|
|
149
|
+
// ValueArrayAddress. Keeping the informary off `.Values` avoids a Number field defaulting it
|
|
150
|
+
// to "0". The descriptor also carries everything the picker needs + the contextual scope hook.
|
|
151
|
+
pRecord.ClauseDescriptor.Address = pRecord.ClauseAddress + '.StringArrayValue';
|
|
152
|
+
pRecord.ClauseDescriptor.DataType = 'String';
|
|
153
|
+
pRecord.ClauseDescriptor.PictForm.InputType = pRecord.ClauseDescriptor.PictForm.InputType || this.options.EntityInputType;
|
|
154
|
+
pRecord.ClauseDescriptor.PictForm.Entity = pRecord.ClauseDescriptor.PictForm.Entity || this.getSearchEntity(pRecord);
|
|
155
|
+
pRecord.ClauseDescriptor.PictForm.ValueField = pRecord.ClauseDescriptor.PictForm.ValueField || this.getLookupColumn(pRecord);
|
|
156
|
+
pRecord.ClauseDescriptor.PictForm.Multiple = this.isMultiSelect();
|
|
157
|
+
pRecord.ClauseDescriptor.PictForm.SearchFields = pRecord.ClauseDescriptor.PictForm.SearchFields
|
|
158
|
+
|| pRecord.ExternalFilterByColumns || (pRecord.ExternalFilterByColumn ? [ pRecord.ExternalFilterByColumn ] : [ 'Name' ]);
|
|
159
|
+
pRecord.ClauseDescriptor.PictForm.ValueArrayAddress = pRecord.ClauseValuesAddress;
|
|
160
|
+
pRecord.ClauseDescriptor.PictForm.GetContextScopeFilter = () => this.getContextScopeFilter(this.getInformaryScopedValue(pRecord.ClauseAddress) || pRecord);
|
|
161
|
+
// JoinEntity compound display (host opt-in on the clause): show each searched row joined to a
|
|
162
|
+
// parent entity's field — e.g. a LineItem disambiguated by its Project. The picker fetch-then-
|
|
163
|
+
// merges the join (Meadow can't join in one read). Forwarded straight through; no-op when unset.
|
|
164
|
+
if (pRecord.JoinEntity || pRecord.ClauseDescriptor.PictForm.JoinEntity)
|
|
165
|
+
{
|
|
166
|
+
const tmpPF = pRecord.ClauseDescriptor.PictForm;
|
|
167
|
+
tmpPF.JoinEntity = tmpPF.JoinEntity || pRecord.JoinEntity;
|
|
168
|
+
tmpPF.JoinField = tmpPF.JoinField || pRecord.JoinField;
|
|
169
|
+
tmpPF.JoinEntityValueField = tmpPF.JoinEntityValueField || pRecord.JoinEntityValueField;
|
|
170
|
+
tmpPF.JoinEntityDisplayField = tmpPF.JoinEntityDisplayField || pRecord.JoinEntityDisplayField;
|
|
171
|
+
if (tmpPF.JoinEntityFirst === undefined && pRecord.JoinEntityFirst !== undefined) { tmpPF.JoinEntityFirst = pRecord.JoinEntityFirst; }
|
|
172
|
+
if (tmpPF.JoinSeparator === undefined && pRecord.JoinSeparator !== undefined) { tmpPF.JoinSeparator = pRecord.JoinSeparator; }
|
|
173
|
+
}
|
|
174
|
+
// Saved-filter seeding: mirror the live clause's Values array into the csv `.StringArrayValue`
|
|
175
|
+
// the input reads, so a reloaded/persisted filter shows its current selections on render.
|
|
176
|
+
const tmpLiveClause = this.getInformaryScopedValue(pRecord.ClauseAddress);
|
|
177
|
+
if (tmpLiveClause && Array.isArray(tmpLiveClause.Values))
|
|
178
|
+
{
|
|
179
|
+
tmpLiveClause.StringArrayValue = tmpLiveClause.Values.join(',');
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
else
|
|
183
|
+
{
|
|
184
|
+
pRecord.ClauseDescriptor.DataType = pRecord.DataType || 'Number';
|
|
185
|
+
}
|
|
186
|
+
if (!pRecord.ExternalFilterTableLookupColumn)
|
|
187
|
+
{
|
|
188
|
+
pRecord.ExternalFilterTableLookupColumn = this.getLookupColumn(pRecord);
|
|
189
|
+
}
|
|
190
|
+
if (!pRecord.SearchResults) { pRecord.SearchResults = []; }
|
|
191
|
+
if (!pRecord.SelectedValues) { pRecord.SelectedValues = []; }
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// --- Table UI search/select methods (consolidated from the 4 legacy views) ---
|
|
195
|
+
|
|
196
|
+
loadMore(pEvent, pClauseInformaryAddress, pClauseHash, pCurrentOffset = 0)
|
|
197
|
+
{
|
|
198
|
+
this.performSearch(pEvent, pClauseInformaryAddress, pClauseHash, pCurrentOffset + this.options.PageSize);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
performSearch(pEvent, pClauseInformaryAddress, pClauseHash, pOffset = 0)
|
|
202
|
+
{
|
|
203
|
+
if (pEvent) { pEvent.preventDefault(); }
|
|
204
|
+
const tmpClause = this.getInformaryScopedValue(pClauseInformaryAddress);
|
|
205
|
+
if (!tmpClause)
|
|
206
|
+
{
|
|
207
|
+
this.pict.log.error(`[Filter-EntityReference] No clause found for address: ${pClauseInformaryAddress}`);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
tmpClause.SearchResultsOffset = pOffset;
|
|
211
|
+
const tmpSearchInputValue = pOffset > 0 ? tmpClause.SearchInputValue : this.pict.ContentAssignment.readContent(`#PRSP_Filter_${tmpClause.Hash}_Search_Value`);
|
|
212
|
+
tmpClause.SearchInputValue = tmpSearchInputValue;
|
|
213
|
+
if (!tmpSearchInputValue)
|
|
214
|
+
{
|
|
215
|
+
tmpClause.SearchResults = [];
|
|
216
|
+
tmpClause.LoadMoreEnabled = false;
|
|
217
|
+
this._reRenderClause(tmpClause, pClauseInformaryAddress, pClauseHash);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
const tmpFilterByColumns = tmpClause.ExternalFilterByColumns || (tmpClause.ExternalFilterByColumn ? [ tmpClause.ExternalFilterByColumn ] : [ 'Name' ]);
|
|
221
|
+
const tmpSearchStanza = tmpFilterByColumns.map((pColumn) => `FBVOR~${pColumn}~LK~${encodeURIComponent(`%${tmpSearchInputValue}%`)}`).join('~');
|
|
222
|
+
const tmpScope = this.getContextScopeFilter(tmpClause);
|
|
223
|
+
const tmpScopeStanza = Array.isArray(tmpScope) ? tmpScope.filter(Boolean).join('~') : tmpScope;
|
|
224
|
+
const tmpMeadowFilter = [ tmpScopeStanza, tmpSearchStanza ].filter(Boolean).join('~');
|
|
225
|
+
this.pict.EntityProvider.gatherDataFromServer(
|
|
226
|
+
[
|
|
227
|
+
{
|
|
228
|
+
Entity: this.getSearchEntity(tmpClause),
|
|
229
|
+
Filter: tmpMeadowFilter,
|
|
230
|
+
Destination: pOffset > 0 ? `${this.getInformaryAddressPrefix()}${pClauseInformaryAddress}.SearchResultsAppend` : `${this.getInformaryAddressPrefix()}${pClauseInformaryAddress}.SearchResults`,
|
|
231
|
+
RecordStartCursor: pOffset,
|
|
232
|
+
PageSize: this.options.PageSize,
|
|
233
|
+
}
|
|
234
|
+
],
|
|
235
|
+
() =>
|
|
236
|
+
{
|
|
237
|
+
if (pOffset > 0 && tmpClause.SearchResultsAppend?.length > 0)
|
|
238
|
+
{
|
|
239
|
+
tmpClause.SearchResults = tmpClause.SearchResults.concat(tmpClause.SearchResultsAppend);
|
|
240
|
+
}
|
|
241
|
+
const tmpLoadedRecords = pOffset > 0 ? tmpClause.SearchResultsAppend : tmpClause.SearchResults;
|
|
242
|
+
delete tmpClause.SearchResultsAppend;
|
|
243
|
+
tmpClause.SearchResultsOffset = pOffset;
|
|
244
|
+
tmpClause.LoadMoreEnabled = tmpLoadedRecords && tmpLoadedRecords.length >= this.options.PageSize;
|
|
245
|
+
this._reRenderClause(tmpClause, pClauseInformaryAddress, pClauseHash);
|
|
246
|
+
if (tmpClause.LoadMoreEnabled)
|
|
247
|
+
{
|
|
248
|
+
this.pict.ContentAssignment.removeClass(`#PRSP_Filter_${tmpClause.Hash}_Button_LoadMore`, 'is-hidden');
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
handleAdd(pEvent, pRecordLookupValue, pClauseInformaryAddress, pClauseHash)
|
|
254
|
+
{
|
|
255
|
+
if (pEvent) { pEvent.preventDefault(); }
|
|
256
|
+
const tmpClause = this.getInformaryScopedValue(pClauseInformaryAddress);
|
|
257
|
+
if (!tmpClause) { return; }
|
|
258
|
+
const tmpRecordLookupColumn = this.getLookupColumn(tmpClause);
|
|
259
|
+
const tmpRecordToAdd = (tmpClause.SearchResults || []).find((pRow) => pRow[tmpRecordLookupColumn] == pRecordLookupValue);
|
|
260
|
+
if (!tmpRecordToAdd) { return; }
|
|
261
|
+
const tmpValue = tmpRecordToAdd[tmpRecordLookupColumn];
|
|
262
|
+
if (tmpValue == null) { return; }
|
|
263
|
+
if (!tmpClause.SelectedValues) { tmpClause.SelectedValues = []; }
|
|
264
|
+
if (!tmpClause.Values) { tmpClause.Values = []; }
|
|
265
|
+
if (this.isMultiSelect())
|
|
266
|
+
{
|
|
267
|
+
if (tmpClause.SelectedValues.some((pSV) => pSV[tmpRecordLookupColumn] == pRecordLookupValue)) { return; }
|
|
268
|
+
tmpClause.SelectedValues.push(tmpRecordToAdd);
|
|
269
|
+
if (!tmpClause.Values.some((pV) => pV == tmpValue)) { tmpClause.Values.push(tmpValue); }
|
|
270
|
+
}
|
|
271
|
+
else
|
|
272
|
+
{
|
|
273
|
+
tmpClause.SelectedValues = [ tmpRecordToAdd ];
|
|
274
|
+
tmpClause.Values = [ tmpValue ];
|
|
275
|
+
}
|
|
276
|
+
this._reRenderClause(tmpClause, pClauseInformaryAddress, pClauseHash);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
handleRemove(pEvent, pRecordLookupValue, pClauseInformaryAddress, pClauseHash)
|
|
280
|
+
{
|
|
281
|
+
if (pEvent) { pEvent.preventDefault(); }
|
|
282
|
+
const tmpClause = this.getInformaryScopedValue(pClauseInformaryAddress);
|
|
283
|
+
if (!tmpClause) { return; }
|
|
284
|
+
const tmpRecordLookupColumn = this.getLookupColumn(tmpClause);
|
|
285
|
+
const tmpIndex = (tmpClause.SelectedValues || []).findIndex((pRow) => pRow[tmpRecordLookupColumn] == pRecordLookupValue);
|
|
286
|
+
if (tmpIndex < 0) { return; }
|
|
287
|
+
const tmpRemoved = tmpClause.SelectedValues.splice(tmpIndex, 1)[0];
|
|
288
|
+
const tmpValue = tmpRemoved[tmpRecordLookupColumn];
|
|
289
|
+
tmpClause.Values = (tmpClause.Values || []).filter((pV) => pV !== tmpValue);
|
|
290
|
+
this._reRenderClause(tmpClause, pClauseInformaryAddress, pClauseHash);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/** Re-render a clause's container (the table UI re-paints on every search / add / remove). */
|
|
294
|
+
_reRenderClause(pClause, pClauseInformaryAddress, pClauseHash)
|
|
295
|
+
{
|
|
296
|
+
const tmpRecord = Object.assign({ ClauseAddress: pClauseInformaryAddress }, pClause);
|
|
297
|
+
this.prepareRecord(tmpRecord);
|
|
298
|
+
this.render(null, `#PRSP_Filter_Container_${pClauseHash}`, tmpRecord);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
module.exports = ViewRecordSetSUBSETFilterEntityReferenceBase;
|
|
303
|
+
|
|
304
|
+
module.exports.default_configuration = Object.assign({}, ViewRecordSetSUBSETFilterBase.default_configuration, _DEFAULT_CONFIGURATION_EntityReference);
|
|
@@ -1,271 +1,25 @@
|
|
|
1
|
+
const ViewRecordSetSUBSETFilterEntityReferenceBase = require('./RecordSet-Filter-EntityReference-Base');
|
|
1
2
|
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const
|
|
3
|
+
// External-join (through a junction table), single-select entity-reference filter. Shared base;
|
|
4
|
+
// entity seam = ExternalFilterByTable, single-select (replace, not append).
|
|
5
|
+
const _DEFAULT_CONFIGURATION =
|
|
5
6
|
{
|
|
6
7
|
ViewIdentifier: 'PRSP-FilterType-ExternalJoinSelectedValue',
|
|
7
|
-
|
|
8
|
-
Templates:
|
|
9
|
-
[
|
|
10
|
-
{
|
|
11
|
-
Hash: 'PRSP-Filter-ExternalJoin-SelectedValue-Template',
|
|
12
|
-
Template: /*html*/`
|
|
13
|
-
<!-- DefaultPackage pict view template: [PRSP-Filter-ExternalJoin-SelectedValue-Template] -->
|
|
14
|
-
<table>
|
|
15
|
-
<tbody>
|
|
16
|
-
<td valign="top">{~T:PRSP-Filter-ExternalJoin-SelectedValue-SearchResults~}</td><td valign="top">{~T:PRSP-Filter-ExternalJoin-SelectedValue-SelectedValues~}</td>
|
|
17
|
-
</tbody>
|
|
18
|
-
</table>
|
|
19
|
-
<!-- DefaultPackage end view template: [PRSP-Filter-ExternalJoin-SelectedValue-Template] -->
|
|
20
|
-
`
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
Hash: 'PRSP-Filter-ExternalJoin-SelectedValue-SearchResults',
|
|
24
|
-
Template: /*html*/`
|
|
25
|
-
<!-- DefaultPackage pict view template: [PRSP-Filter-ExternalJoin-SearchResults] -->
|
|
26
|
-
<form id="PRSP_Filter_{~D:Record.Hash~}_Search_Form" onsubmit="_Pict.views['{~D:Context[0].Hash~}'].performSearch(event, '{~D:Record.ClauseAddress~}', '{~D:Record.Hash~}'); return false;">
|
|
27
|
-
<input id="PRSP_Filter_{~D:Record.Hash~}_Search_Value" type="text" placeholder="Search..." value="{~D:Record.SearchInputValue~}" />
|
|
28
|
-
<button type="submit" id="PRSP_Filter_{~D:Record.Hash~}_Button_Search" onclick="_Pict.views['{~D:Context[0].Hash~}'].performSearch(event, '{~D:Record.ClauseAddress~}', '{~D:Record.Hash~}')">Search</button>
|
|
29
|
-
</form>
|
|
30
|
-
<table>
|
|
31
|
-
<thead>
|
|
32
|
-
<tr><th colspan="2">{~D:Record.Label~}</th></tr>
|
|
33
|
-
</thead>
|
|
34
|
-
<tbody>
|
|
35
|
-
{~TSWP:PRSP-Filter-ExternalJoin-SelectedValue-SearchResults-Entry:Record.SearchResults:Record~}
|
|
36
|
-
</tbody>
|
|
37
|
-
</table>
|
|
38
|
-
<button type="button" id="PRSP_Filter_{~D:Record.Hash~}_Button_LoadMore" class="is-hidden" onclick="_Pict.views['{~D:Context[0].Hash~}'].loadMore(event, '{~D:Record.ClauseAddress~}', '{~D:Record.Hash~}', {~D:Record.SearchResultsOffset:0~})">Load More</button>
|
|
39
|
-
<!-- DefaultPackage end view template: [PRSP-Filter-ExternalJoin-SearchResults] -->
|
|
40
|
-
`
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
Hash: 'PRSP-Filter-ExternalJoin-SelectedValue-SelectedValues',
|
|
44
|
-
Template: /*html*/`
|
|
45
|
-
<!-- DefaultPackage view template: [PRSP-Filter-ExternalJoin-SelectedValue-SelectedValues] -->
|
|
46
|
-
<table>
|
|
47
|
-
<thead>
|
|
48
|
-
<tr><th colspan="2">Selection</th></tr>
|
|
49
|
-
</thead>
|
|
50
|
-
<tbody>
|
|
51
|
-
{~TSWP:PRSP-Filter-ExternalJoin-SelectedValue-SelectedValues-Entry:Record.SelectedValues:Record~}
|
|
52
|
-
</tbody>
|
|
53
|
-
</table>
|
|
54
|
-
<!-- DefaultPackage end view template: [PRSP-Filter-ExternalJoin-SelectedValue-SelectedValues] -->
|
|
55
|
-
`
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
Hash: 'PRSP-Filter-ExternalJoin-SelectedValue-SearchResults-Entry',
|
|
59
|
-
Template: /*html*/`
|
|
60
|
-
<!-- DefaultPackage pict view template: [PRSP-Filter-ExternalJoin-SelectedValue-Template] -->
|
|
61
|
-
<tr><td><button onclick="_Pict.views['{~D:Context[0].Hash~}'].handleSelect(event, {~DVBK:Record.Data:Record.Payload.ExternalFilterTableLookupColumn~}, '{~D:Record.Payload.ClauseAddress~}', '{~D:Record.Payload.Hash~}')">Select</button></td><td>{~TFA:Record.Payload.ExternalRecordDisplayTemplate:Record~}</td></tr>
|
|
62
|
-
<!-- DefaultPackage end view template: [PRSP-Filter-ExternalJoin-SelectedValue-Template] -->
|
|
63
|
-
`
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
Hash: 'PRSP-Filter-ExternalJoin-SelectedValue-SelectedValues-Entry',
|
|
67
|
-
Template: /*html*/`
|
|
68
|
-
<!-- DefaultPackage pict view template: [PRSP-Filter-ExternalJoin-SelectedValue-SelectedValues-Entry] -->
|
|
69
|
-
<tr><td><button onclick="_Pict.views['{~D:Context[0].Hash~}'].handleRemove(event, {~DVBK:Record.Data:Record.Payload.ExternalFilterTableLookupColumn~}, '{~D:Record.Payload.ClauseAddress~}', '{~D:Record.Payload.Hash~}')">Remove</button></td><td>{~TFA:Record.Payload.ExternalRecordDisplayTemplate:Record~}</td></tr>
|
|
70
|
-
<!-- DefaultPackage end view template: [PRSP-Filter-ExternalJoin-SelectedValue-SelectedValues-Entry] -->
|
|
71
|
-
`
|
|
72
|
-
}
|
|
73
|
-
],
|
|
74
8
|
};
|
|
75
9
|
|
|
76
|
-
class ViewRecordSetSUBSETFilterExternalJoinSelectedValue extends
|
|
10
|
+
class ViewRecordSetSUBSETFilterExternalJoinSelectedValue extends ViewRecordSetSUBSETFilterEntityReferenceBase
|
|
77
11
|
{
|
|
78
|
-
|
|
79
|
-
{
|
|
80
|
-
if (!pOptions.PageSize)
|
|
81
|
-
{
|
|
82
|
-
pOptions.PageSize = 15; // default page size for search results
|
|
83
|
-
}
|
|
84
|
-
super(pFable, pOptions, pServiceHash);
|
|
85
|
-
/*
|
|
86
|
-
* show / hide the complex editor since it'll be large ?
|
|
87
|
-
* selected record lookup values
|
|
88
|
-
* using bundle to load those records (if any)
|
|
89
|
-
* templating out the selection
|
|
90
|
-
* templating out the search results
|
|
91
|
-
* controls to add search result values to selection
|
|
92
|
-
*/
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* @param {Record<string, any>} pRecord
|
|
97
|
-
*/
|
|
98
|
-
prepareRecord(pRecord)
|
|
99
|
-
{
|
|
100
|
-
super.prepareRecord(pRecord);
|
|
101
|
-
|
|
102
|
-
pRecord.ClauseDescriptor.DataType = pRecord.DataType || 'Number';
|
|
103
|
-
pRecord.ClauseDescriptor.PictForm = pRecord.PictForm || {};
|
|
104
|
-
if (!pRecord.ExternalFilterTableLookupColumn)
|
|
105
|
-
{
|
|
106
|
-
pRecord.ExternalFilterTableLookupColumn = `ID${pRecord.ExternalFilterByTable}`;
|
|
107
|
-
}
|
|
108
|
-
if (!pRecord.SearchResults)
|
|
109
|
-
{
|
|
110
|
-
pRecord.SearchResults = [];
|
|
111
|
-
}
|
|
112
|
-
if (!pRecord.SelectedValues)
|
|
113
|
-
{
|
|
114
|
-
pRecord.SelectedValues = [];
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
getFilterFormTemplate()
|
|
119
|
-
{
|
|
120
|
-
return 'PRSP-Filter-ExternalJoin-SelectedValue-Template';
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* @param {UIEvent} pEvent
|
|
125
|
-
* @param {string} pClauseInformaryAddress
|
|
126
|
-
* @param {string} pClauseHash
|
|
127
|
-
*/
|
|
128
|
-
loadMore(pEvent, pClauseInformaryAddress, pClauseHash, pCurrentOffset = 0)
|
|
129
|
-
{
|
|
130
|
-
this.performSearch(pEvent, pClauseInformaryAddress, pClauseHash, pCurrentOffset + this.options.PageSize);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* @param {UIEvent} pEvent
|
|
135
|
-
* @param {string} pClauseInformaryAddress
|
|
136
|
-
* @param {string} pClauseHash
|
|
137
|
-
* @param {number} [pOffset=0] - The offset for the search results, defaults to 0
|
|
138
|
-
*/
|
|
139
|
-
performSearch(pEvent, pClauseInformaryAddress, pClauseHash, pOffset = 0)
|
|
140
|
-
{
|
|
141
|
-
pEvent.preventDefault();
|
|
142
|
-
const tmpClause = this.getInformaryScopedValue(pClauseInformaryAddress);
|
|
143
|
-
if (!tmpClause)
|
|
144
|
-
{
|
|
145
|
-
this.pict.log.error(`[Filter-ExternalJoinSelectedValue] No clause found for address: ${pClauseInformaryAddress}`);
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
tmpClause.SearchResultsOffset = pOffset;
|
|
149
|
-
// get the input value (search box)
|
|
150
|
-
const tmpSearchInputValue = pOffset > 0 ? tmpClause.SearchInputValue : this.pict.ContentAssignment.readContent(`#PRSP_Filter_${tmpClause.Hash}_Search_Value`);
|
|
151
|
-
tmpClause.SearchInputValue = tmpSearchInputValue;
|
|
152
|
-
if (!tmpSearchInputValue)
|
|
153
|
-
{
|
|
154
|
-
tmpClause.SearchResults = [];
|
|
155
|
-
tmpClause.LoadMoreEnabled = false;
|
|
156
|
-
const tmpRecord = Object.assign({ ClauseAddress: pClauseInformaryAddress }, tmpClause);
|
|
157
|
-
this.prepareRecord(tmpRecord);
|
|
158
|
-
const tmpDestinationAddress = `#PRSP_Filter_Container_${pClauseHash}`;
|
|
159
|
-
this.render(null, tmpDestinationAddress, tmpRecord);
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
const tmpFilterByColumns = tmpClause.ExternalFilterByColumns || (tmpClause.ExternalFilterByColumn ? [ tmpClause.ExternalFilterByColumn ] : [ 'Name' ]);
|
|
163
|
-
const tmpMeadowFilter = tmpFilterByColumns.map((pColumn) => `FBVOR~${pColumn}~LK~${encodeURIComponent(`%${tmpSearchInputValue}%`)}`).join('~');
|
|
164
|
-
// bundle load the remote records and put them in the clause
|
|
165
|
-
this.pict.EntityProvider.gatherDataFromServer(
|
|
166
|
-
[
|
|
167
|
-
{
|
|
168
|
-
Entity: tmpClause.ExternalFilterByTable,
|
|
169
|
-
Filter: tmpMeadowFilter,
|
|
170
|
-
Destination: pOffset > 0 ? `${this.getInformaryAddressPrefix()}${pClauseInformaryAddress}.SearchResultsAppend` : `${this.getInformaryAddressPrefix()}${pClauseInformaryAddress}.SearchResults`,
|
|
171
|
-
RecordStartCursor: pOffset,
|
|
172
|
-
PageSize: this.options.PageSize,
|
|
173
|
-
}
|
|
174
|
-
],
|
|
175
|
-
(pError, pResult) =>
|
|
176
|
-
{
|
|
177
|
-
if (pOffset > 0 && tmpClause.SearchResultsAppend?.length > 0)
|
|
178
|
-
{
|
|
179
|
-
tmpClause.SearchResults = tmpClause.SearchResults.concat(tmpClause.SearchResultsAppend);
|
|
180
|
-
}
|
|
181
|
-
delete tmpClause.SearchResultsAppend;
|
|
182
|
-
tmpClause.SearchResultsOffset = pOffset;
|
|
183
|
-
const tmpRecord = Object.assign({ ClauseAddress: pClauseInformaryAddress }, tmpClause);
|
|
184
|
-
this.prepareRecord(tmpRecord);
|
|
185
|
-
const tmpDestinationAddress = `#PRSP_Filter_Container_${pClauseHash}`;
|
|
186
|
-
this.render(null, tmpDestinationAddress, tmpRecord);
|
|
187
|
-
const tmpLoadedRecords = pOffset > 0 ? tmpClause.SearchResultsAppend : tmpClause.SearchResults;
|
|
188
|
-
const tmpLoadMoreEnabled = tmpLoadedRecords && tmpLoadedRecords.length >= this.options.PageSize;
|
|
189
|
-
tmpClause.LoadMoreEnabled = tmpLoadMoreEnabled;
|
|
190
|
-
if (tmpClause.LoadMoreEnabled)
|
|
191
|
-
{
|
|
192
|
-
this.pict.ContentAssignment.removeClass(`#PRSP_Filter_${tmpClause.Hash}_Button_LoadMore`, 'is-hidden');
|
|
193
|
-
}
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
handleSelect(pEvent, pRecordLookupValue, pClauseInformaryAddress, pClauseHash)
|
|
12
|
+
getSearchEntity(pClause)
|
|
198
13
|
{
|
|
199
|
-
|
|
200
|
-
const tmpClause = this.getInformaryScopedValue(pClauseInformaryAddress);
|
|
201
|
-
if (!tmpClause)
|
|
202
|
-
{
|
|
203
|
-
this.pict.log.error(`[Filter-ExternalJoinSelectedValue] No clause found for address: ${pClauseInformaryAddress}`);
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
const tmpRecordLookupColumn = tmpClause.ExternalFilterTableLookupColumn || `ID${tmpClause.ExternalFilterByTable}`;
|
|
207
|
-
const tmpRecordToSelect = tmpClause.SearchResults.find((r) => r[tmpRecordLookupColumn] == pRecordLookupValue);
|
|
208
|
-
if (!tmpRecordToSelect)
|
|
209
|
-
{
|
|
210
|
-
this.pict.log.error(`[Filter-ExternalJoinSelectedValue] No record found to add for value: ${pRecordLookupValue}`);
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
if (!tmpClause.SelectedValues)
|
|
214
|
-
{
|
|
215
|
-
tmpClause.SelectedValues = [];
|
|
216
|
-
}
|
|
217
|
-
if (tmpClause.SelectedValues.some((pSV) => pSV[tmpRecordLookupColumn] == pRecordLookupValue))
|
|
218
|
-
{
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
const tmpValue = tmpRecordToSelect[tmpRecordLookupColumn];
|
|
222
|
-
if (tmpValue == null)
|
|
223
|
-
{
|
|
224
|
-
this.pict.log.error(`[Filter-ExternalJoinSelectedValue] No value found in record to add: ${JSON.stringify(tmpRecordToSelect)}`);
|
|
225
|
-
return;
|
|
226
|
-
}
|
|
227
|
-
tmpClause.SelectedValues = [ tmpRecordToSelect ];
|
|
228
|
-
tmpClause.Values = [ tmpValue ];
|
|
229
|
-
const tmpRecord = Object.assign({ ClauseAddress: pClauseInformaryAddress }, tmpClause);
|
|
230
|
-
this.prepareRecord(tmpRecord);
|
|
231
|
-
const tmpDestinationAddress = `#PRSP_Filter_Container_${pClauseHash}`;
|
|
232
|
-
this.render(null, tmpDestinationAddress, tmpRecord);
|
|
233
|
-
if (tmpClause.LoadMoreEnabled)
|
|
234
|
-
{
|
|
235
|
-
this.pict.ContentAssignment.removeClass(`#PRSP_Filter_${tmpClause.Hash}_Button_LoadMore`, 'is-hidden');
|
|
236
|
-
}
|
|
14
|
+
return pClause.ExternalFilterByTable;
|
|
237
15
|
}
|
|
238
16
|
|
|
239
|
-
|
|
17
|
+
isMultiSelect()
|
|
240
18
|
{
|
|
241
|
-
|
|
242
|
-
const tmpClause = this.getInformaryScopedValue(pClauseInformaryAddress);
|
|
243
|
-
if (!tmpClause)
|
|
244
|
-
{
|
|
245
|
-
this.pict.log.error(`[Filter-ExternalJoinSelectedValue] No clause found for address: ${pClauseInformaryAddress}`);
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
248
|
-
const tmpRecordLookupColumn = tmpClause.ExternalFilterTableLookupColumn || `ID${tmpClause.ExternalFilterByTable}`;
|
|
249
|
-
const tmpRecordIndexToRemove = tmpClause.SelectedValues.findIndex((r) => r[tmpRecordLookupColumn] == pRecordLookupValue);
|
|
250
|
-
if (tmpRecordIndexToRemove < 0)
|
|
251
|
-
{
|
|
252
|
-
this.pict.log.error(`[Filter-ExternalJoinSelectedValue] No record found to remove for value: ${pRecordLookupValue}`);
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
255
|
-
const tmpRecordToRemove = tmpClause.SelectedValues.splice(tmpRecordIndexToRemove, 1)[0];
|
|
256
|
-
const tmpValue = tmpRecordToRemove[tmpRecordLookupColumn];
|
|
257
|
-
tmpClause.Values = tmpClause.Values.filter((pV) => pV !== tmpValue);
|
|
258
|
-
const tmpRecord = Object.assign({ ClauseAddress: pClauseInformaryAddress }, tmpClause);
|
|
259
|
-
this.prepareRecord(tmpRecord);
|
|
260
|
-
const tmpDestinationAddress = `#PRSP_Filter_Container_${pClauseHash}`;
|
|
261
|
-
this.render(null, tmpDestinationAddress, tmpRecord);
|
|
262
|
-
if (tmpClause.LoadMoreEnabled)
|
|
263
|
-
{
|
|
264
|
-
this.pict.ContentAssignment.removeClass(`#PRSP_Filter_${tmpClause.Hash}_Button_LoadMore`, 'is-hidden');
|
|
265
|
-
}
|
|
19
|
+
return false;
|
|
266
20
|
}
|
|
267
21
|
}
|
|
268
22
|
|
|
269
23
|
module.exports = ViewRecordSetSUBSETFilterExternalJoinSelectedValue;
|
|
270
24
|
|
|
271
|
-
module.exports.default_configuration = Object.assign({},
|
|
25
|
+
module.exports.default_configuration = Object.assign({}, ViewRecordSetSUBSETFilterEntityReferenceBase.default_configuration, _DEFAULT_CONFIGURATION);
|