pict-section-recordset 1.0.57 → 1.0.59

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.
Files changed (46) hide show
  1. package/docs/.nojekyll +0 -0
  2. package/docs/README.md +76 -0
  3. package/docs/_sidebar.md +19 -0
  4. package/docs/api-reference.md +233 -0
  5. package/docs/cover.md +11 -0
  6. package/docs/filters.md +151 -0
  7. package/docs/index.html +51 -0
  8. package/docs/record-providers.md +155 -0
  9. package/docs/views/create/README.md +181 -0
  10. package/docs/views/dashboard/README.md +308 -0
  11. package/docs/views/list/README.md +260 -0
  12. package/docs/views/read/README.md +216 -0
  13. package/example_applications/README.md +25 -1
  14. package/package.json +11 -10
  15. package/source/application/Pict-Application-RecordSet.js +6 -0
  16. package/source/providers/Filter-Data-Provider.js +611 -187
  17. package/source/views/Filter-PersistenceView.js +534 -0
  18. package/source/views/RecordSet-Filters.js +141 -28
  19. package/test/PictSectionRecordSet-Basic_tests.js +39 -16
  20. package/test/PictSectionRecordSet-Filter-Data-Provider_tests.js +263 -0
  21. package/test/PictSectionRecordSet-RecordProvider-Meadow_tests.js +5 -3
  22. package/types/application/Pict-Application-RecordSet.d.ts.map +1 -1
  23. package/types/providers/Filter-Data-Provider.d.ts +225 -52
  24. package/types/providers/Filter-Data-Provider.d.ts.map +1 -1
  25. package/types/views/Filter-PersistenceView.d.ts +104 -0
  26. package/types/views/Filter-PersistenceView.d.ts.map +1 -0
  27. package/types/views/RecordSet-Filters.d.ts +43 -10
  28. package/types/views/RecordSet-Filters.d.ts.map +1 -1
  29. package/types/views/filters/RecordSet-Filter-Base-Range.d.ts.map +1 -1
  30. package/types/views/filters/RecordSet-Filter-Base.d.ts.map +1 -1
  31. package/types/views/filters/RecordSet-Filter-DateMatch.d.ts.map +1 -1
  32. package/types/views/filters/RecordSet-Filter-DateRange.d.ts.map +1 -1
  33. package/types/views/filters/RecordSet-Filter-ExternalJoinDateMatch.d.ts.map +1 -1
  34. package/types/views/filters/RecordSet-Filter-ExternalJoinDateRange.d.ts.map +1 -1
  35. package/types/views/filters/RecordSet-Filter-ExternalJoinNumericMatch.d.ts.map +1 -1
  36. package/types/views/filters/RecordSet-Filter-ExternalJoinNumericRange.d.ts.map +1 -1
  37. package/types/views/filters/RecordSet-Filter-ExternalJoinSelectedValue.d.ts.map +1 -1
  38. package/types/views/filters/RecordSet-Filter-ExternalJoinSelectedValueList.d.ts.map +1 -1
  39. package/types/views/filters/RecordSet-Filter-InternalJoinDateMatch.d.ts.map +1 -1
  40. package/types/views/filters/RecordSet-Filter-InternalJoinDateRange.d.ts.map +1 -1
  41. package/types/views/filters/RecordSet-Filter-InternalJoinNumericMatch.d.ts.map +1 -1
  42. package/types/views/filters/RecordSet-Filter-InternalJoinNumericRange.d.ts.map +1 -1
  43. package/types/views/filters/RecordSet-Filter-InternalJoinSelectedValue.d.ts.map +1 -1
  44. package/types/views/filters/RecordSet-Filter-InternalJoinSelectedValueList.d.ts.map +1 -1
  45. package/types/views/filters/RecordSet-Filter-NumericMatch.d.ts.map +1 -1
  46. package/types/views/filters/RecordSet-Filter-NumericRange.d.ts.map +1 -1
@@ -0,0 +1,534 @@
1
+ const libPictView = require('pict-view');
2
+
3
+ const _DEFAULT_CONFIGURATION_FilterPersistenceView = (
4
+ {
5
+ ViewIdentifier: 'FilterPersistenceView',
6
+
7
+ DefaultRenderable: 'FilterPersistenceView-Container',
8
+ DefaultDestinationAddress: '#FilterPersistenceView-Container',
9
+ DefaultTemplateRecordAddress: false,
10
+
11
+ // If this is set to true, when the App initializes this will.
12
+ // While the App initializes, initialize will be called.
13
+ AutoInitialize: false,
14
+ AutoInitializeOrdinal: 0,
15
+
16
+ // If this is set to true, when the App autorenders (on load) this will.
17
+ // After the App initializes, render will be called.
18
+ AutoRender: false,
19
+ AutoRenderOrdinal: 0,
20
+
21
+ AutoSolveWithApp: false,
22
+ AutoSolveOrdinal: 0,
23
+
24
+ CSS: false,
25
+ CSSPriority: 500,
26
+
27
+ Templates:
28
+ [
29
+ {
30
+ Hash: 'FilterPersistenceView-Container',
31
+ Template: /*html*/`
32
+ <!-- DefaultPackage pict view template: [FilterPersistenceView-Container] -->
33
+ <div id="FilterPersistenceView-Content">
34
+ <!-- Content for Filter Persistence View goes here -->
35
+ <div id="FilterPersistenceView-Header">
36
+ <h3>Filter Experience Settings</h3>
37
+ </div>
38
+ <div id="FilterPersistenceView-Body">
39
+ <div class="FilterPersistenceView-ActiveSettings">
40
+ <label for="CurrentFilterName">Current Filter Experience:</label>
41
+ <span id="FilterPersistenceView-CurrentFilterNameInput-ValidationMessage" style="color: red; font-size: 0.9em; margin-left: 10px;"></span>
42
+ <input type="text" id="FilterPersistenceView-CurrentFilterNameInput" name="CurrentFilterName" value="" onfocus="this.select()" />
43
+ <button type="button" id="FilterPersistenceView-SaveFilterButton" onclick="_Pict.views['FilterPersistenceView'].saveFilterPersistenceSettings(event)">
44
+ <span id="FilterPersistenceView-SaveFilterButtonText">Save</span>
45
+ </button>
46
+ </div>
47
+ <div class="FilterPersistenceView-StoredSettings">
48
+ <label for="StoredFilterName">Stored Filter Experiences:</label>
49
+ <select id="FilterPersistenceView-StoredFiltersSelect" onchange="_Pict.views['FilterPersistenceView'].setFilterExperienceToSelection(event)" name="StoredFilterName">
50
+ <!-- Options will be populated dynamically -->
51
+ </select>
52
+ <button type="button" id="FilterPersistenceView-LoadFilterButton" onclick="_Pict.views['FilterPersistenceView'].loadFilterPersistenceSettings(event)">Load</button>
53
+ <button type="button" id="FilterPersistenceView-SetAsDefaultButton" onclick="_Pict.views['FilterPersistenceView'].toggleFilterExperienceAsTheDefault(event, true)">Set As Default</button>
54
+ <button type="button" id="FilterPersistenceView-RemoveAsDefaultButton" onclick="_Pict.views['FilterPersistenceView'].toggleFilterExperienceAsTheDefault(event, false)">Remove As Default</button>
55
+ <button type="button" id="FilterPersistenceView-DeleteFilterButton" onclick="_Pict.views['FilterPersistenceView'].deleteFilterPersistenceSettings(event)">Delete</button>
56
+ </div>
57
+ <div class="FilterPersistenceView-OptionalSettings">
58
+ <label for="OptionalSettings">Optional Settings:</label>
59
+ <label for="OptionalSettings-RememberLastUsed">
60
+ <input type="checkbox" id="OptionalSettings-RememberLastUsed" name="RememberLastUsed" onchange="_Pict.views['FilterPersistenceView'].toggleRememberLastUsedFilterExperience(event)" />
61
+ Remember my last search filter experience
62
+ </label>
63
+ </div>
64
+ </div>
65
+ <div id="FilterPersistenceView-Footer">
66
+ <button type="button" id="FilterPersistenceView-CloseManageFiltersButton" onclick="_Pict.views['FilterPersistenceView'].closeFilterPersistenceUI()">Close</button>
67
+ </div>
68
+ </div>
69
+ <!-- DefaultPackage end view template: [FilterPersistenceView-Container] -->
70
+ `
71
+ }
72
+ ],
73
+
74
+ Renderables:
75
+ [
76
+ {
77
+ RenderableHash: 'FilterPersistenceView-Renderable',
78
+ TemplateHash: 'FilterPersistenceView-Container',
79
+ DestinationAddress: '#FilterPersistenceView-Container',
80
+ RenderMethod: 'replace'
81
+ },
82
+
83
+ ],
84
+
85
+ Manifests: {}
86
+ });
87
+
88
+ class viewFilterPersistenceView extends libPictView
89
+ {
90
+ constructor(pFable, pOptions, pServiceHash)
91
+ {
92
+ let tmpOptions = Object.assign({}, _DEFAULT_CONFIGURATION_FilterPersistenceView, pOptions);
93
+ super(pFable, tmpOptions, pServiceHash);
94
+
95
+ this.currentRecordSet = null;
96
+ this.currentViewContext = null;
97
+ this.filterExperienceSelection = null;
98
+ this.filterExperienceInitialized = false;
99
+ }
100
+
101
+
102
+ /**
103
+ * Initializes the filter persistence view UI for a given record set and view context. This will render the UI and populate it with the relevant filter experiences for the given context.
104
+ * @param {string} pRecordSet - The identifier of the record set.
105
+ * @param {string} pViewContext - The context of the view.
106
+ * @param {function} pCallback - A callback function to be executed after initializing the UI.
107
+ * @returns {boolean} - Returns true when the UI has been initialized.
108
+ */
109
+ initializeFilterPersistenceViewUI(pRecordSet, pViewContext, pCallback)
110
+ {
111
+ if (!pRecordSet || !pViewContext)
112
+ {
113
+ this.pict.log.error('RecordSet and ViewContext are required to open the Filter Persistence UI.');
114
+ return false;
115
+ }
116
+
117
+ if (!this.filterExperienceInitialized)
118
+ {
119
+ this.pict.providers.FilterDataProvider.initializeFilterExperienceSettings(pRecordSet, pViewContext);
120
+ this.filterExperienceInitialized = true;
121
+ }
122
+ this.currentRecordSet = pRecordSet;
123
+ this.currentViewContext = pViewContext;
124
+ // Implement the logic for toggling filter persistence UI here
125
+ this.render('FilterPersistenceView-Renderable', undefined, { RecordSet: pRecordSet, ViewContext: pViewContext });
126
+
127
+ // set checkbox for "Remember Last Used Filter Experience" based on provider setting
128
+ const checkboxElement = document.getElementById('OptionalSettings-RememberLastUsed');
129
+ if (checkboxElement)
130
+ {
131
+ // @ts-ignore
132
+ checkboxElement.checked = this.pict.providers.FilterDataProvider.getRememberLastUsedFilterExperience(this.currentRecordSet, this.currentViewContext);
133
+ }
134
+ // build the select options for available filter experiences
135
+ this.buildSelectOptionsForAvailableFilterExperiences();
136
+ this.handleModifiedFiltersState();
137
+
138
+ // if a callback function was provided, execute it after the UI has been generated
139
+ if (pCallback && typeof pCallback === 'function')
140
+ {
141
+ pCallback();
142
+ };
143
+ return true;
144
+ }
145
+
146
+ /**
147
+ * Updates the current filter experience name in the input field based on the current filter experience applied for the given record set and view context. This is used to ensure that if the filter experience was modified outside of the UI (ex: through the URL hash), we can reflect that in the input field and also handle the button states accordingly to prevent unintended consequences of saving in an invalid state.
148
+ * @param {string} pRecordSet - The identifier of the record set.
149
+ * @param {string} pViewContext - The context of the view.
150
+ * @param {boolean} pIgnoreCurrentExperienceURLParam - Whether to ignore the current experience when updating the input field, use this when in a modified state and the url is now outdated, to generate a new name.
151
+ */
152
+ updateDisplayNameInputWithCurrentFilterExperience(pRecordSet, pViewContext, pIgnoreCurrentExperienceURLParam = false)
153
+ {
154
+ const tmpFilterExperienceList = this.pict.providers.FilterDataProvider.getAllFiltersExperiencesForRecordSet(pRecordSet, pViewContext);
155
+ // get the current filter experience hash from the URL
156
+ const tmpExperienceURLParam = this.pict.providers.PictRouter?.router?.current?.[0].hashString?.split?.('/FilterExperience/')?.[1] || '';
157
+ // look in the map for the filter experience with the given hash
158
+ const filterExperiences = this.pict.providers.FilterDataProvider.getAllFiltersExperiencesForRecordSet(pRecordSet, pViewContext);
159
+ // BUG?: We are doing a double lookup here to match both the name and the encoded URL param, because just looking up by URL param alone can lead to issues if there are multiple experiences with the same URL param but different names.
160
+ const matchingExperience = filterExperiences.find((pExperience) => pExperience.FilterExperienceHash === tmpFilterExperienceList.find((exp) => exp.FilterExperienceEncodedURLParam === tmpExperienceURLParam)?.FilterExperienceHash);
161
+ // If we found a matching experience (both name and encoded URL param), set it as the current filter name and the active selection in the selector
162
+ if (!pIgnoreCurrentExperienceURLParam && matchingExperience && (matchingExperience.FilterExperienceEncodedURLParam === tmpExperienceURLParam))
163
+ {
164
+ this.pict.providers.FilterDataProvider.setCurrentFilterName(matchingExperience, pRecordSet, pViewContext);
165
+ this.filterExperienceSelection = matchingExperience.FilterExperienceHash;
166
+ // check if the current filter experience is set as default on load, so we can set the button states accordingly
167
+ const isDefault = this.pict.providers.FilterDataProvider.isDefaultFilterExperience(pRecordSet, pViewContext, this.filterExperienceSelection);
168
+ this.handleSelectionButtonStates(isDefault);
169
+ }
170
+ else
171
+ {
172
+ this.pict.providers.FilterDataProvider.setCurrentFilterName(null, pRecordSet, pViewContext, null);
173
+ this.filterExperienceSelection = null;
174
+ this.handleSelectionButtonStates(null);
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Toggles the filter persistence UI for a given record set and view context
180
+ * @param {string} pRecordSet - The identifier of the record set.
181
+ * @param {string} pViewContext - The context of the view.
182
+ * @param {function} pCallback - A callback function to be executed after toggling the UI.
183
+ * @returns {boolean} - Returns true when the UI has been toggled.
184
+ */
185
+ openFilterPersistenceUI(pRecordSet, pViewContext, pCallback)
186
+ {
187
+ // hide the button that was just clicked on (will use a different button to close the UI)
188
+ if (document.getElementById('PRSP_Filter_Button_Manage'))
189
+ {
190
+ document.getElementById('PRSP_Filter_Button_Manage').style.display = 'none';
191
+ }
192
+ // render the UI for managing filter persistence settings
193
+ this.initializeFilterPersistenceViewUI(pRecordSet, pViewContext, pCallback);
194
+ return true;
195
+ }
196
+
197
+ /**
198
+ * Handles the state of the filter experience when it has been modified from the URL hash instead of through the UI, which can lead to an invalid state for saving if the user tries to save without realizing the current experience was modified outside of the UI.
199
+ * This method will show a warning message and disable the save/set as default/remove as default/delete buttons to prevent unintended consequences of saving in that state, and will prompt the user to load a filter experience through the UI or refresh the page to reset the state before they can save. It will also disable the current filter name input and set a warning message in it to indicate that the user needs to apply or reset filters changes to be able to save settings. If the filter experience is not in that modified state, it will ensure the buttons are enabled and the current filter name input is enabled and populated with the current filter experience name for better visibility when saving.
200
+ */
201
+ handleModifiedFiltersState()
202
+ {
203
+ // if the current filter experience was modified from the URL hash, show a warning toast to the user that they need to load a filter experience through the UI or refresh the page to reset the state before they can save, since saving in that state could lead to unintended consequences of saving an unintended filter experience as the default or overwriting an existing filter experience without realizing it
204
+ if (this.pict.providers.FilterDataProvider.filterExperienceModifiedFromURLHash)
205
+ {
206
+ // disable the save and set as default buttons to prevent saving in this state
207
+ this.pict.ContentAssignment.setAttribute('#FilterPersistenceView-SaveFilterButton', 'disabled', 'disabled');
208
+ this.pict.ContentAssignment.setAttribute('#FilterPersistenceView-SetAsDefaultButton', 'disabled', 'disabled');
209
+ this.pict.ContentAssignment.setAttribute('#FilterPersistenceView-RemoveAsDefaultButton', 'disabled', 'disabled');
210
+ this.pict.ContentAssignment.setAttribute('#FilterPersistenceView-DeleteFilterButton', 'disabled', 'disabled');
211
+ this.pict.ContentAssignment.assignContent('#FilterPersistenceView-CurrentFilterNameInput-ValidationMessage', 'Please apply or reset filter changes to enable saving settings.');
212
+ this.pict.ContentAssignment.setAttribute('#FilterPersistenceView-CurrentFilterNameInput', 'title', 'The current filter experience has been modified. Please apply or reset filter changes to enable saving settings and set a default filter experience.');
213
+ this.pict.ContentAssignment.setAttribute('#FilterPersistenceView-CurrentFilterNameInput', 'disabled', 'disabled');
214
+ }
215
+ else
216
+ {
217
+ // re-enable the buttons in case they were disabled from being in a modified state, to allow saving and setting default again
218
+ this.pict.ContentAssignment.removeAttribute('#FilterPersistenceView-SaveFilterButton', 'disabled');
219
+ this.pict.ContentAssignment.removeAttribute('#FilterPersistenceView-SetAsDefaultButton', 'disabled');
220
+ this.pict.ContentAssignment.removeAttribute('#FilterPersistenceView-RemoveAsDefaultButton', 'disabled');
221
+ this.pict.ContentAssignment.removeAttribute('#FilterPersistenceView-DeleteFilterButton', 'disabled');
222
+ this.pict.ContentAssignment.assignContent('#FilterPersistenceView-CurrentFilterNameInput-ValidationMessage', '');
223
+ this.pict.ContentAssignment.setAttribute('#FilterPersistenceView-CurrentFilterNameInput', 'title', '');
224
+ this.pict.ContentAssignment.removeAttribute('#FilterPersistenceView-CurrentFilterNameInput', 'disabled');
225
+ }
226
+ // regardless of the modified state, update the current filter name input to match the current filter experience for better visibility when saving and to ensure it reflects any changes that may have happened to the filter experience from the URL hash or elsewhere
227
+ this.updateDisplayNameInputWithCurrentFilterExperience(this.currentRecordSet, this.currentViewContext, this.pict.providers.FilterDataProvider.filterExperienceModifiedFromURLHash);
228
+ }
229
+
230
+ /**
231
+ * Updates the filter experience settings for a given record set and view context.
232
+ * @param {string} pRecordSet - The identifier of the record set.
233
+ * @param {string} pViewContext - The context of the view.
234
+ * @param {object} pSettings - The settings to update.
235
+ * @returns {boolean} - Returns true when the settings have been updated.
236
+ */
237
+ updateFilterExperienceSettings(pRecordSet, pViewContext, pSettings)
238
+ {
239
+ if (pRecordSet && pViewContext)
240
+ {
241
+ this.pict.providers.FilterDataProvider.initializeFilterExperienceSettings(pRecordSet, pViewContext);
242
+ this.currentRecordSet = pRecordSet;
243
+ this.currentViewContext = pViewContext;
244
+ // for any settings that may have changed, update those without replacing the whole settings object
245
+ this.pict.providers.FilterDataProvider.updateFilterExperienceSettingsFromStorage(pRecordSet, pViewContext, pSettings);
246
+ // build the select options for available filter experiences
247
+ this.buildSelectOptionsForAvailableFilterExperiences();
248
+ }
249
+ return true;
250
+ }
251
+
252
+ /**
253
+ * Sets the filter experience to load based on user selection.
254
+ * @param {Event} event - The event object.
255
+ * @returns {boolean} - Returns true when the filter experience has been set.
256
+ */
257
+ setFilterExperienceToSelection(event)
258
+ {
259
+ event.preventDefault();
260
+ event.stopPropagation();
261
+
262
+ this.filterExperienceSelection = this.pict.ContentAssignment.readContent('#FilterPersistenceView-StoredFiltersSelect');
263
+ // check if the selected filter experience is set as default on load, so we can set the button states accordingly
264
+ const isDefault = this.pict.providers.FilterDataProvider.isDefaultFilterExperience(this.currentRecordSet, this.currentViewContext, this.filterExperienceSelection);
265
+ this.handleSelectionButtonStates(isDefault);
266
+ // set the current filter name in the provider to match the selection
267
+ const tmpSelectedFilterExperience = this.pict.providers.FilterDataProvider.getFilterExperienceByHash(this.currentRecordSet, this.currentViewContext, this.filterExperienceSelection);
268
+ let tmpBackupDisplayName = '';
269
+ if (!tmpSelectedFilterExperience)
270
+ {
271
+ tmpBackupDisplayName = `New ${this.currentRecordSet} ${this.currentViewContext} Filter`;
272
+ }
273
+ this.pict.providers.FilterDataProvider.setCurrentFilterName(tmpSelectedFilterExperience, this.currentRecordSet, this.currentViewContext, tmpBackupDisplayName);
274
+ // update the save button to text to be "Update" instead of "Save" if the selected filter experience is the current one, to indicate that clicking it will update the existing filter experience instead of creating a new one
275
+ if (this.filterExperienceSelection && this.pict.providers.FilterDataProvider.isCurrentFilterExperience(this.currentRecordSet, this.currentViewContext, this.filterExperienceSelection))
276
+ {
277
+ this.pict.ContentAssignment.assignContent('#FilterPersistenceView-SaveFilterButtonTextText', 'Update');
278
+ }
279
+ else
280
+ {
281
+ this.pict.ContentAssignment.assignContent('#FilterPersistenceView-SaveFilterButtonTextText', 'Save');
282
+ }
283
+ return true;
284
+ }
285
+
286
+ /**
287
+ * Closes the filter persistence UI.
288
+ * @returns {boolean} - Returns true when the UI has been closed.
289
+ */
290
+ closeFilterPersistenceUI()
291
+ {
292
+ this.currentRecordSet = null;
293
+ this.currentViewContext = null;
294
+ this.filterExperienceSelection = null;
295
+ this.handleSelectionButtonStates(null);
296
+ // show the button that was hidden when opening the UI
297
+ if (document.getElementById('PRSP_Filter_Button_Manage'))
298
+ {
299
+ document.getElementById('PRSP_Filter_Button_Manage').style.display = 'inline-block';
300
+ }
301
+ // Clear the content of the Filter Persistence View (if it's still on the DOM - it will re-render next time it's opened either way, but this is to ensure we don't have stale content if the view is still around in the DOM)
302
+ if (document.getElementById('FilterPersistenceView-Content'))
303
+ {
304
+ document.getElementById('FilterPersistenceView-Content').innerHTML = '';
305
+ }
306
+ return true;
307
+ }
308
+
309
+ /**
310
+ * Builds the select options for available filter experiences. Sets the current filter as selected and indicates it in the option text.
311
+ * @returns {boolean} - Returns true when the options have been built.
312
+ */
313
+ buildSelectOptionsForAvailableFilterExperiences()
314
+ {
315
+ let optionList = []
316
+ const filterExperienceList = this.pict.providers.FilterDataProvider.getAllFiltersExperiencesForRecordSet(this.currentRecordSet, this.currentViewContext);
317
+ // add a default option at the top
318
+ optionList.push('<option value="">-- Select a stored Filter Experience --</option>');
319
+ // iterate through the filter experiences and build the option elements
320
+ for (const key in filterExperienceList)
321
+ {
322
+ // skip excluded ones (if needed for hidden/internal use)
323
+ if (filterExperienceList[key].ExcludedFromSelection)
324
+ {
325
+ continue;
326
+ }
327
+ // if the current filter is the active/default one, mention that in the option text for clarity
328
+ const isCurrent = this.pict.providers.FilterDataProvider.isCurrentFilterExperience(this.currentRecordSet, this.currentViewContext, filterExperienceList[key].FilterExperienceHash);
329
+ const isDefault = this.pict.providers.FilterDataProvider.isDefaultFilterExperience(this.currentRecordSet, this.currentViewContext, filterExperienceList[key].FilterExperienceHash);
330
+ let addOnText = '';
331
+ if (isCurrent)
332
+ {
333
+ addOnText += ' (Current)';
334
+ }
335
+ if (isDefault)
336
+ {
337
+ addOnText += ' (Default)';
338
+ }
339
+ const optionElement = `<option ${ isCurrent ? 'selected' : ''} value="${filterExperienceList[key].FilterExperienceHash}">${filterExperienceList[key].FilterDisplayName || filterExperienceList[key].FilterExperienceHash}${addOnText}</option>`;
340
+ optionList.push(optionElement);
341
+ }
342
+ /* @type {HTMLSelectElement} */
343
+ const storedFiltersSelect = document.getElementById('FilterPersistenceView-StoredFiltersSelect');
344
+ if (storedFiltersSelect)
345
+ {
346
+ storedFiltersSelect.innerHTML = optionList.join('\n');
347
+ }
348
+ // after rebuilding the options, if there is a current selection, ensure the save button text is correct based on whether the current selection is the active filter experience or not
349
+ if (this.filterExperienceSelection && this.pict.providers.FilterDataProvider.isCurrentFilterExperience(this.currentRecordSet, this.currentViewContext, this.filterExperienceSelection))
350
+ {
351
+ this.pict.ContentAssignment.assignContent('#FilterPersistenceView-SaveFilterButtonText', 'Update');
352
+ }
353
+ else
354
+ {
355
+ this.pict.ContentAssignment.assignContent('#FilterPersistenceView-SaveFilterButtonText', 'Save');
356
+ }
357
+ return true;
358
+ }
359
+
360
+ /**
361
+ * Toggles the "Remember Last Used Filter Experience" setting in the Filter Data Provider.
362
+ * @param {Event} event - The event object.
363
+ * @returns {boolean} - Returns true when the setting has been toggled.
364
+ */
365
+ toggleRememberLastUsedFilterExperience(event)
366
+ {
367
+ event.preventDefault();
368
+ event.stopPropagation();
369
+
370
+ const checkboxElement = document.getElementById('OptionalSettings-RememberLastUsed');
371
+ // @ts-ignore
372
+ const rememberLastUsed = checkboxElement ? checkboxElement.checked : false;
373
+
374
+ this.pict.providers.FilterDataProvider.setRememberLastUsedFilterExperience(this.currentRecordSet, this.currentViewContext, rememberLastUsed);
375
+ this.pict.log.info(`Remember Last Used Filter Experience has been ${rememberLastUsed ? 'enabled' : 'disabled'}.`);
376
+ return true;
377
+ }
378
+
379
+ /**
380
+ * Loads the filter persistence settings for the current selection of filter experiences.
381
+ * @param {Event} event - The event object.
382
+ * @returns {boolean} - Returns true when the settings have been loaded.
383
+ */
384
+ loadFilterPersistenceSettings(event, pCallback)
385
+ {
386
+ event.preventDefault();
387
+ event.stopPropagation();
388
+ const selectedFilterExperienceHash = this.filterExperienceSelection;
389
+ if (!selectedFilterExperienceHash)
390
+ {
391
+ this.pict.log.warn('No filter experience selected to load.');
392
+ return false;
393
+ }
394
+ this.pict.providers.FilterDataProvider.loadFilterMeta(this.currentRecordSet, this.currentViewContext, selectedFilterExperienceHash);
395
+ this.pict.log.info(`Filter persistence settings have been loaded for filter: ${selectedFilterExperienceHash}`);
396
+ this.pict.providers.FilterDataProvider.filterExperienceModifiedFromURLHash = false;
397
+ // if a callback function was provided, execute it after loading the settings (toasts, etc.)
398
+ if (pCallback && typeof pCallback === 'function')
399
+ {
400
+ pCallback();
401
+ }
402
+ return true;
403
+ }
404
+
405
+ /**
406
+ * Saves the filter persistence settings for the current selection of filter experiences.
407
+ * @param {Event} event - The event object.
408
+ * @param {function} [pCallback] - A callback function to be executed after saving the settings.
409
+ * @returns {boolean} - Returns true when the settings have been saved.
410
+ */
411
+ saveFilterPersistenceSettings(event, pCallback)
412
+ {
413
+ event.preventDefault();
414
+ event.stopPropagation();
415
+
416
+ if (!this.currentRecordSet || !this.currentViewContext)
417
+ {
418
+ this.pict.log.warn('Missing a record set or view context to save filter persistence settings. Skipping save. CurrentRecordSet: ' + this.currentRecordSet + ', CurrentViewContext: ' + this.currentViewContext + ')');
419
+ return false;
420
+ }
421
+
422
+ if (this.pict.providers.FilterDataProvider.filterExperienceModifiedFromURLHash)
423
+ {
424
+ this.pict.log.warn('The current filter experience has been modified from the URL hash and not through the UI, so it may not be in a valid state to save. Please load a filter experience through the UI or refresh the page to reset the state before saving.');
425
+ return false;
426
+ }
427
+
428
+ this.pict.providers.FilterDataProvider.saveFilterMeta(this.currentRecordSet, this.currentViewContext, false);
429
+ this.buildSelectOptionsForAvailableFilterExperiences();
430
+ this.pict.log.info('Filter persistence settings have been saved.');
431
+ // if a callback function was provided, execute it after saving the settings (toasts, etc.)
432
+ if (pCallback && typeof pCallback === 'function')
433
+ {
434
+ pCallback();
435
+ }
436
+ return true;
437
+ }
438
+
439
+ /**
440
+ * Sets the filter experience as the default for the current record set and view context.
441
+ * @param {Event} event - The event object.
442
+ * @param {boolean} isDefault - Whether to set as default or not.
443
+ * @param {function} [pCallback] - A callback function to be executed after toggling the default setting.
444
+ * @returns {boolean} - Returns true when the settings have been set as default.
445
+ */
446
+ toggleFilterExperienceAsTheDefault(event, isDefault, pCallback)
447
+ {
448
+ event.preventDefault();
449
+ event.stopPropagation();
450
+
451
+ const selectedFilterExperienceHash = this.filterExperienceSelection;
452
+ if (!selectedFilterExperienceHash)
453
+ {
454
+ this.pict.log.warn('No filter experience selected to set as default.');
455
+ return false;
456
+ }
457
+ // set or unset the default filter experience on load in the provider
458
+ this.pict.providers.FilterDataProvider.setDefaultFilterExperience(this.currentRecordSet, this.currentViewContext, selectedFilterExperienceHash, isDefault);
459
+ this.handleSelectionButtonStates(isDefault);
460
+
461
+ this.buildSelectOptionsForAvailableFilterExperiences();
462
+ this.pict.log.info(`Filter experience ${selectedFilterExperienceHash} has been ${isDefault ? 'set' : 'unset'} as the default on load.`);
463
+ // if a callback function was provided, execute it after setting the default (toasts, etc.)
464
+ if (pCallback && typeof pCallback === 'function')
465
+ {
466
+ pCallback();
467
+ }
468
+ return true;
469
+ }
470
+
471
+ /**
472
+ * Handles the button states for the filter experience selection.
473
+ * @param {boolean} isDefault - Whether the filter experience is set as default or not.
474
+ */
475
+ handleSelectionButtonStates(isDefault)
476
+ {
477
+ if (!this.filterExperienceSelection)
478
+ {
479
+ this.pict.ContentAssignment.setAttribute('#FilterPersistenceView-LoadFilterButton', 'style', 'display: none;');
480
+ this.pict.ContentAssignment.setAttribute('#FilterPersistenceView-SetAsDefaultButton', 'style', 'display: none;');
481
+ this.pict.ContentAssignment.setAttribute('#FilterPersistenceView-RemoveAsDefaultButton', 'style', 'display: none;');
482
+ this.pict.ContentAssignment.setAttribute('#FilterPersistenceView-DeleteFilterButton', 'style', 'display: none;');
483
+ return;
484
+ }
485
+ else
486
+ {
487
+ this.pict.ContentAssignment.setAttribute('#FilterPersistenceView-LoadFilterButton', 'style', 'display: inline-block;');
488
+ this.pict.ContentAssignment.setAttribute('#FilterPersistenceView-DeleteFilterButton', 'style', 'display: inline-block;');
489
+ }
490
+ // handle the set/remove default buttons separately when we have a selection
491
+ if (isDefault)
492
+ {
493
+ this.pict.ContentAssignment.setAttribute('#FilterPersistenceView-SetAsDefaultButton', 'style', 'display: none;');
494
+ this.pict.ContentAssignment.setAttribute('#FilterPersistenceView-RemoveAsDefaultButton', 'style', 'display: inline-block;');
495
+ }
496
+ else
497
+ {
498
+ this.pict.ContentAssignment.setAttribute('#FilterPersistenceView-SetAsDefaultButton', 'style', 'display: inline-block;');
499
+ this.pict.ContentAssignment.setAttribute('#FilterPersistenceView-RemoveAsDefaultButton', 'style', 'display: none;');
500
+ }
501
+ }
502
+
503
+ /**
504
+ * Deletes the filter persistence settings for the current selection of filter experiences.
505
+ * @param {Event} event - The event object.
506
+ * @param {function} [pCallback] - A callback function to be executed after deleting the settings.
507
+ * @returns {boolean} - Returns true when the settings have been deleted.
508
+ */
509
+ deleteFilterPersistenceSettings(event, pCallback)
510
+ {
511
+ event.preventDefault();
512
+ event.stopPropagation();
513
+
514
+ const selectedFilterExperienceHash = this.filterExperienceSelection;
515
+ if (!selectedFilterExperienceHash)
516
+ {
517
+ this.pict.log.warn('No filter experience selected to delete.');
518
+ return false;
519
+ }
520
+ this.pict.providers.FilterDataProvider.removeFilterMeta(this.currentRecordSet, this.currentViewContext, selectedFilterExperienceHash);
521
+ this.buildSelectOptionsForAvailableFilterExperiences();
522
+ this.pict.log.info(`Filter persistence settings have been deleted for filter: ${selectedFilterExperienceHash}`);
523
+ // if a callback function was provided, execute it after deleting the settings (toasts, etc.)
524
+ if (pCallback && typeof pCallback === 'function')
525
+ {
526
+ pCallback();
527
+ }
528
+ return true;
529
+ }
530
+ }
531
+
532
+ module.exports = viewFilterPersistenceView;
533
+
534
+ module.exports.default_configuration = _DEFAULT_CONFIGURATION_FilterPersistenceView;