@nys-cui/cui-formpill 0.2.9 → 0.2.20

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 (41) hide show
  1. package/component-base/README.md +43 -0
  2. package/component-base/cui.jsonc +6 -0
  3. package/component-base/package.json +42 -0
  4. package/component-base/src/assets/scss/_button-menu.scss +270 -0
  5. package/component-base/src/assets/scss/_buttons.scss +200 -0
  6. package/component-base/src/assets/scss/_cui-asof.scss +86 -0
  7. package/component-base/src/assets/scss/_cui-formpill.scss +284 -0
  8. package/component-base/src/assets/scss/_cui-general.scss +19 -0
  9. package/component-base/src/assets/scss/_cui-message.scss +119 -0
  10. package/component-base/src/assets/scss/_cui-spinner.scss +27 -0
  11. package/component-base/src/assets/scss/_cui-tree.scss +136 -0
  12. package/component-base/src/assets/scss/_cui-widget.scss +128 -0
  13. package/component-base/src/assets/scss/_field-check-group.scss +296 -0
  14. package/component-base/src/assets/scss/_field-radio-group.scss +236 -0
  15. package/component-base/src/assets/scss/_fonts.scss +20 -0
  16. package/component-base/src/assets/scss/_globalNotes.scss +419 -0
  17. package/component-base/src/assets/scss/_grid.scss +489 -0
  18. package/component-base/src/assets/scss/_help.scss +46 -0
  19. package/component-base/src/assets/scss/_inputs.scss +1145 -0
  20. package/component-base/src/assets/scss/_modal.scss +56 -0
  21. package/component-base/src/assets/scss/_normalize.scss +3 -0
  22. package/component-base/src/assets/scss/_popovers.scss +119 -0
  23. package/component-base/src/assets/scss/_quick_lookup.scss +87 -0
  24. package/component-base/src/assets/scss/_sidebar-context.scss +896 -0
  25. package/component-base/src/assets/scss/_table.scss +702 -0
  26. package/component-base/src/assets/scss/_toast.scss +219 -0
  27. package/component-base/src/assets/scss/_utility.scss +64 -0
  28. package/component-base/src/assets/scss/_variables.scss +58 -0
  29. package/component-base/src/assets/scss/main.scss +451 -0
  30. package/component-base/src/assets/scss/normalize/_import-now.scss +11 -0
  31. package/component-base/src/assets/scss/normalize/_normalize-mixin.scss +570 -0
  32. package/component-base/src/assets/scss/normalize/_variables.scss +37 -0
  33. package/component-base/src/assets/scss/normalize/_vertical-rhythm.scss +63 -0
  34. package/component-base/src/assets/scss/readme.md +1 -0
  35. package/component-base/src/modules/dom.js +21 -0
  36. package/component-base/src/screens/index/cui.jsonc +3 -0
  37. package/component-base/src/screens/index/index.js +228 -0
  38. package/component-base/src/screens/index/index.tpl.html +32 -0
  39. package/component-base/src/spa.js +117 -0
  40. package/package.json +1 -1
  41. package/src/cui-formpill.js +452 -999
@@ -11,15 +11,18 @@ class CUI_FORMPILL_PILL extends HTMLElement {
11
11
  this._state = {};
12
12
 
13
13
  this.oPropsToStateNames = {
14
- "text": "sText",
15
- "value1": "sValue1",
16
- "value2": "sValue2",
17
- "value3": "sValue3",
18
- "values": "asValues"
14
+ "label": "sLabel",
15
+ "value": "sValue",
16
+ "fields": "aoFieldValues",
17
+ "valueLabel": "sValueLabel",
18
+ "charLimit": 'iCharLimit'
19
19
  }
20
20
 
21
+ this._state.iCharLimit = 30;
21
22
  this._state.sPosition = 'bottom-center'
22
23
 
24
+ this.cValidator = new VALIDATOR();
25
+
23
26
  }
24
27
 
25
28
  get state() {
@@ -29,21 +32,13 @@ class CUI_FORMPILL_PILL extends HTMLElement {
29
32
 
30
33
 
31
34
  get contents() {
32
- if (this._state.sValue3) {
33
- return {
34
- 'fieldName': this._state.sValue1,
35
- 'operator': this._state.sValue2,
36
- 'value': this._state.sValue3
37
- }
38
- } else if (this._state.asValues) {
39
- return {
40
- 'fieldName': this._state.sValue1,
41
- 'value': this._state.asValues.split(',')
42
- }
43
- } else {
35
+
36
+ if (this._state.aoFieldValues && this._state.sValue) {
44
37
  return {
45
- 'fieldName': this._state.sValue1,
46
- 'value': this._state.sValue2
38
+ 'value': this._state.sValue,
39
+ 'fields': this._state.aoFieldValues,
40
+ 'label': this._state.sLabel,
41
+ 'valueLabel': this._state.sValueLabel
47
42
  }
48
43
  }
49
44
  }
@@ -83,12 +78,8 @@ class CUI_FORMPILL_PILL extends HTMLElement {
83
78
  return sTemplate;
84
79
 
85
80
  }
81
+
86
82
  connectedCallback() {
87
- this._state.sText = (this.getAttribute('text')) ? this.getAttribute('text') : "";
88
- this._state.sValue1 = (this.getAttribute('value1')) ? this.getAttribute('value1') : null;
89
- this._state.sValue2 = (this.getAttribute('value2')) ? this.getAttribute('value2') : null;
90
- this._state.sValue3 = (this.getAttribute('value3')) ? this.getAttribute('value3') : null;
91
- this._state.asValues = (this.getAttribute('values')) ? this.getAttribute('values') : null;
92
83
 
93
84
  this._connected = true;
94
85
  this.render();
@@ -127,7 +118,10 @@ class CUI_FORMPILL_PILL extends HTMLElement {
127
118
 
128
119
  const title = document.createElement('div');
129
120
  title.classList.add('pill-title');
130
- title.innerText = this._state.sText;
121
+
122
+ let label = this._state.sLabel + ": " + this._state.sValueLabel;
123
+ label = label.slice(0, this._state.iCharLimit) + (label.length > this._state.iCharLimit ? "..." : "");
124
+ title.innerText = label;
131
125
 
132
126
  formPill.appendChild(title);
133
127
 
@@ -155,34 +149,29 @@ class CUI_FORMPILL_PILL extends HTMLElement {
155
149
  }
156
150
  }
157
151
  }
158
-
159
-
160
152
  }
161
153
 
162
154
  customElements.define('cui-formpill-pill', CUI_FORMPILL_PILL);
163
155
 
164
156
  class CUI_FORMPILL extends HTMLElement {
157
+
165
158
  constructor() {
166
159
  super();
167
160
  this._connected = false;
168
161
  this.attachShadow({ mode: 'open' });
169
162
 
170
163
  this._state = {};
171
- this._initialState = null;
164
+ this._initialState = {};
172
165
 
173
166
  this._state.bMenuDisplayed = false;
174
167
 
175
- this._state.aMenuContents = [];
176
-
177
168
  this._state.sHtmlContent = null;
178
169
 
179
170
  this.dLabelContents;
180
171
 
181
- this._state.configData = null;
182
-
183
- this._state.adPills = [];
172
+ this._state.aoConfig = null;
184
173
 
185
- this._state.criteriaList = null;
174
+ this._state.sCriteriaList = new Set();
186
175
 
187
176
  this.oPropsToStateNames = {
188
177
  "text": "sTextContent",
@@ -193,17 +182,40 @@ class CUI_FORMPILL extends HTMLElement {
193
182
  "iconbase": "sIconBasePath",
194
183
  "accessibleHideLabel": "bAccessibleHideLabel",
195
184
  "html": "sHtmlContent",
196
- "config": "configData",
185
+ "config": "aoConfig",
197
186
  "addTitle": "sAddTitle",
198
187
  "updateTitle": "sUpdateTitle",
199
- "value": "aoValue"
188
+ "pills": "aoPills"
200
189
 
201
190
  }
202
191
 
203
192
  this.cValidator = new VALIDATOR();
193
+
204
194
  }
205
195
 
206
- get sFieldLayout() {
196
+ get footer() {
197
+ return `<div class="grid button-row">
198
+ <div class="row">
199
+ <div class="col-full align-end">
200
+ <cui-button class="addBtn" text="Add" primary="true"></cui-button>
201
+ <cui-button class="resetBtn" text="Clear"></cui-button>
202
+ </div>
203
+ </div>
204
+ </div>`
205
+ }
206
+
207
+ get pillFooter() {
208
+ return `<div class="grid button-row">
209
+ <div class="row">
210
+ <div class="col-full align-end">
211
+ <cui-button class="updateBtn" text="Update" primary="true"></cui-button>
212
+ <cui-button class="resetBtn" text="Reset"></cui-button>
213
+ </div>
214
+ </div>
215
+ </div>`
216
+ }
217
+
218
+ get sShadowLayout() {
207
219
  return `
208
220
  <div class="cui-field" part="outer-wrapper">
209
221
  <div class="cui-label " part="label-wrapper">
@@ -214,108 +226,110 @@ class CUI_FORMPILL extends HTMLElement {
214
226
  </div>`;
215
227
  }
216
228
 
217
- setInitialState(state) {
218
- for (let [k, v] of Object.entries(this._state)) {
219
- switch (k) {
220
- case "adPills":
221
- this._initialState[k] = [];
222
- for (let pill of v) {
223
- let copiedPill = document.createElement("cui-formpill-pill");
224
- if (!state) {
225
- for (const attrValue of structuredClone(pill.getAttributeNames()))
226
- copiedPill.setAttribute(attrValue, pill.getAttribute(attrValue));
227
-
228
- } else {
229
-
230
- for (const attrValue of structuredClone(pill.getAttributeNames()))
231
- copiedPill.setAttribute(attrValue, pill._state[pill.oPropsToStateNames[attrValue]]);
232
-
233
- }
234
- this._initialState[k].push(copiedPill);
235
-
236
- }
237
- break;
238
-
239
- case "criteriaList":
240
- this._initialState[k] = structuredClone(v);
241
- break;
242
-
243
- case "configData":
244
- this._initialState[k] = structuredClone(v);
245
- break;
246
-
247
- default:
248
- this._initialState[k] = v;
249
-
250
- }
251
-
252
- }
229
+ get sLightLayout() {
230
+ return `
231
+ <label slot="labelContents" for="${this._state.sComponentKey}">${!this._state.bAccessibleHideLabel ? (this._state.sLabel + ":") : ""}</label>
232
+ <div class="pill-container" part="pill-container" slot="pill-container"></div>
233
+ <button id="button-menu-trigger" class="button-menu-trigger" title="${this._state.sLabel}" part="menu-trigger" slot="menu-trigger" type="button" aria-label="${this._state.sLabel} aria-controls="popover" aria-haspopup="true">
234
+ ${this._state.sIconBasePath ? `<cui-icon src="${this._state.sIconBasePath}" class="accessibleHideLabel"></cui-icon>` : `<div class="add-icon" part="add-icon">+</div>`}
235
+ ${!this._state.bAccessibleHideLabel ? this._state.sLabel : ""}
236
+ </button>`;
237
+ }
238
+
239
+ sPopoverLayout(forPill) {
240
+ return `
241
+ <cui-formpill-popover class="${!this.bMobile ? 'button-menu' : ''}" style="z-index:900">
242
+ <${!this.bMobile ? 'div' : 'dialog'} class="${this.bMobile ? 'dialog-popover-contents' : 'popover-contents'}" slot="popover-contents">
243
+ <div class="popover-body">
244
+ <div class="popover-header">
245
+ <h3>${forPill ? this._state.sUpdateTitle : this._state.sAddTitle}</h3>
246
+ <button class="close-button">×</button>
247
+ </div>
248
+ <div class="body-content"></div>
249
+ <div class="popover-footer">
250
+ ${forPill ? this.pillFooter : this.footer}
251
+ </div>
252
+ </div>
253
+ </${!this.bMobile ? 'div' : 'dialog'}>
254
+ </cui-formpill-popover>
255
+ `
253
256
  }
254
257
 
255
258
  setState(props, bOverrideInitialState = false) {
256
259
  // Need to map props to state variable names if we want to keep them prefixed.
257
- if (!this._initialState) this._initialState = {};
258
260
 
259
261
  this._state = Object.assign(this._state, this.normalizeProps(props));
260
262
 
261
- if (this._connected) {
262
- this.render();
263
+ if (bOverrideInitialState) {
264
+ this._initialState = this.updateState(this._state);
263
265
  }
264
266
 
265
- if (bOverrideInitialState) {
266
- if (this._connected) {
267
- this.setInitialState(true);
268
- } else {
269
- this.setInitialState();
270
- }
267
+ if (this._connected) {
268
+ this.render();
271
269
  }
272
270
  }
273
- reset() {
274
271
 
275
- for (const [k, v] of Object.entries(this._initialState)) {
276
- switch (k) {
277
- case "adPills":
278
- this._state[k] = [];
279
- for (const pill of v) {
280
- const myEvent = new CustomEvent("pill-removed", {
281
- detail: { pill: pill }
282
- });
283
- this.dispatchEvent(myEvent);
284
- let copiedPill = document.createElement("cui-formpill-pill");
285
- for (const attrValue of structuredClone(pill.getAttributeNames())) {
286
- copiedPill.setAttribute(attrValue, pill.getAttribute(attrValue));
272
+ updateState(state) {
273
+
274
+ let initialState = {};
275
+
276
+ for (let [key, vvalue] of Object.entries(state)) {
277
+ switch (key) {
278
+ case "aoPills":
279
+ initialState[key] = [];
280
+ for (let pill of vvalue) {
281
+ // Clone the DOM node
282
+ let dPillClone = null;
283
+ if (pill.dPill) {
284
+ dPillClone = pill.dPill.cloneNode(true);
287
285
  }
288
- this._state[k].push(copiedPill);
289
286
 
287
+ // Make a shallow copy of pill and remove dPill before deep cloning
288
+ const tempPill = { ...pill };
289
+ delete tempPill.dPill;
290
+
291
+ // Deep clone the pill object without dPill
292
+ let pillClone = structuredClone(tempPill);
293
+
294
+ // Assign the cloned DOM node back
295
+ if (dPillClone) {
296
+ pillClone.dPill = dPillClone;
297
+ }
298
+
299
+ initialState[key].push(pillClone);
290
300
  }
291
301
  break;
292
-
293
- case "criteriaList":
294
- this._state[k] = structuredClone(v);
302
+ default:
303
+ initialState[key] = structuredClone(vvalue);
295
304
  break;
305
+ }
306
+ }
296
307
 
297
- case "configData":
298
- this._state[k] = structuredClone(v);
299
- break;
308
+ return initialState;
309
+ }
300
310
 
301
- default:
302
- this._state[k] = v;
311
+ reset() {
312
+ if (this._initialState) {
313
+ this._state = this.updateState(this._initialState);
303
314
 
315
+ if (this._cMessageList) {
316
+ this._cMessageList.reset();
304
317
  }
305
318
 
306
- }
319
+ if (this._state.dMenuPopover) {
320
+ this._state.dMenuPopover.state.bOpen = false;
321
+ document.body.removeChild(this._state.dMenuPopover)
322
+ this._state.dMenuPopover = null;
323
+ document.body.removeEventListener('click', this.fGlobalBodyClick);
324
+ this._state.bMenuDisplayed = false;
325
+ }
307
326
 
308
- if (this._state.dMenuPopover) {
309
- this._state.dMenuPopover.state.bOpen = false;
310
- document.body.removeChild(this._state.dMenuPopover)
311
- this._state.dMenuPopover = null;
312
- document.body.removeEventListener('click', this.fGlobalBodyClick);
313
- this._state.bMenuDisplayed = false;
314
- }
315
327
 
328
+ this.render();
316
329
 
317
- this.render(true);
330
+ }
318
331
  }
332
+
319
333
  get label() {
320
334
 
321
335
  if (this.dLabelContents) {
@@ -354,12 +368,10 @@ class CUI_FORMPILL extends HTMLElement {
354
368
  // Call above setting connected to avoid second render.
355
369
  this._connected = true;
356
370
 
357
- //Set initial menu object based on children.
358
-
359
- var match = window.matchMedia || window.msMatchMedia;
360
-
371
+ //Checking media type to decide if it is in mobile device
372
+ let match = window.matchMedia || window.msMatchMedia;
361
373
  if (match) {
362
- var mq = match("(pointer:coarse)");
374
+ let mq = match("(pointer:coarse)");
363
375
  this.bMobile = mq.matches;
364
376
  }
365
377
 
@@ -373,1034 +385,458 @@ class CUI_FORMPILL extends HTMLElement {
373
385
  this._state.bAccessibleHideLabel = this.hasAttribute('accessiblehidelabel') ? true : false;
374
386
  this._state.sPosition = (this.getAttribute('position')) ? this.getAttribute('position') : "bottom-center";
375
387
  this._state.aoValue = (this.getAttribute('value')) ? this.getAttribute('value') : [];
388
+ this._state.iCharLimit = (this.getAttribute('charLimit')) ? this.getAttribute('charLimit') : null;
389
+ this._state.isMultiple = (this.hasAttribute('isMultiple')) ? true : false;
376
390
 
377
- //Set initial state only once at connection to page. At this point any initial data should have been passed to the field.
378
- if (!this._initialState || this._initialState == null) {
379
- // Shallow clone for now unless it's determined we need a deep clone.
380
- this._initialState = {};
381
- }
382
-
391
+ //Click Event listener for the window
383
392
  this.fGlobalBodyClick = this.globalBodyClick.bind(this);
384
393
 
385
- this.setInitialState();
386
394
  this.render();
387
395
  }
388
396
 
389
- get footer() {
390
- return `<div class="grid button-row">
391
- <div class="row">
392
- <div class="col-full align-end">
393
- <cui-button class="addBtn" text="Add" primary="true"></cui-button>
394
- <cui-button class="resetBtn" text="Clear"></cui-button>
395
- </div>
396
- </div>
397
- </div>`
398
- }
399
-
400
- get pillFooter() {
401
- return `<div class="grid button-row">
402
- <div class="row">
403
- <div class="col-full align-end">
404
- <cui-button class="updateBtn" text="Update" primary="true"></cui-button>
405
- <cui-button class="resetBtn" text="Reset"></cui-button>
406
- </div>
407
- </div>
408
- </div>`
409
- }
410
397
 
411
- render(reset = false) {
398
+ render() {
412
399
  this.clearShadowDom(this.shadowRoot);
413
400
  this.clearSlottedElements("menu-trigger");
414
401
  this.clearSlottedElements("labelContents");
415
402
  this.clearSlottedElements("pill-container");
416
403
 
417
- this.shadowRoot.innerHTML = `${this.sFieldLayout} `;
418
-
419
-
420
- if (this._state.adPills.length > 0) {
421
- for (let pill of this._state.adPills) {
422
-
423
- let removedValue = pill._state.sValue1;
424
-
425
- const initialIndex = this._initialState.configData.filterCriteria.items.findIndex(item => item.value === removedValue);
426
-
427
-
428
- // Check if the item is already in criteriaList
429
- if (!this._state.criteriaList.some(item => item.value === removedValue)) {
430
- // Find the item in configData.filterCriteria.items
431
- const itemToAdd = this._state.configData.filterCriteria.items.find(item => item.value === removedValue);
432
- if (itemToAdd) {
433
- // Insert the item at the same position as in _initialState
434
- if (initialIndex !== -1) {
435
- this._state.criteriaList.splice(initialIndex, 0, itemToAdd);
436
- } else {
437
- // If the item is not found in _initialState, default to adding at the end
438
- this._state.criteriaList.push(itemToAdd);
439
- }
440
- }
441
- }
442
- }
443
- }
404
+ this.shadowRoot.innerHTML = `${this.sShadowLayout} `;
405
+ this.innerHTML = `${this.sLightLayout}`
444
406
 
407
+ this.dTrigger = this.querySelector('button.button-menu-trigger')
445
408
 
409
+ this.dTrigger.addEventListener('click', async (event) => {
410
+ this.menuTriggerOnClick();
411
+ });
446
412
 
447
- this._state.adPills = [];
448
-
449
- if (this._state.configData?.filterCriteria && !this._state.configData.filterCriteria.loadedPills) {
450
- this._state.configData.filterCriteria.loadedPills = []
451
- }
452
-
453
- if (this._state.aoValue && this._state.aoValue.length > 0 && this._state.configData?.filterCriteria?.loadedPills && reset === false) {
454
- this._state.configData.filterCriteria.loadedPills = []
455
- for (let pill of this._state.aoValue) {
456
- this._state.configData.filterCriteria.loadedPills.push(pill);
457
- }
458
- this.addPillfromJSON();
459
-
460
- } else if (reset === true) {
461
- if (this._state.configData?.filterCriteria?.loadedPills) {
462
-
463
- this._state.configData.filterCriteria.loadedPills = []
464
- }
465
- this.addPillfromJSON();
466
- }
467
-
413
+ window.addEventListener('resize', (e) => {
414
+ this.windowResize(e);
415
+ window.removeEventListener('resize', this.windowResize())
416
+ });
468
417
 
469
418
 
470
- let adSlots = this.shadowRoot.querySelectorAll('slot');
419
+ //Load pills from state if they already exists.
420
+ if (this?._state?.aoPills?.length) {
421
+ for (let oPill of this._state.aoPills) {
471
422
 
472
- if (adSlots.length) {
423
+ if (this?._state?.aoConfig?.items) {
473
424
 
474
- for (let dSlot of adSlots) {
475
- let dNode = dSlot.assignedNodes()[0];
425
+ let oMatchedItem = this._state.aoConfig.items.find(item => item.value === oPill.value);
476
426
 
477
- if (dNode) {
478
- let sSlotName = dNode.getAttribute("slot");
427
+ let sLabel = oMatchedItem ? oMatchedItem.label : '';
479
428
 
480
- if (sSlotName && sSlotName.toLowerCase() === "labelcontents") {
481
- this.dLabelContents = dNode;
482
- }
429
+ oPill.label = sLabel;
483
430
 
431
+ let dPill = this.#createAndAppendPill(oPill, true);
432
+ oPill.dPill = dPill;
484
433
  }
485
434
 
435
+ this._state.sCriteriaList.add(oPill.value)
486
436
  }
487
-
488
437
  }
489
-
490
- let label = document.createElement('label');
491
- label.slot = 'labelContents';
492
-
493
- label.setAttribute('for', this._state.sComponentKey)
494
-
495
- let pillDiv = document.createElement('div');
496
- pillDiv.classList.add('pill-container');
497
- pillDiv.part = "pill-container"
498
- pillDiv.slot = "pill-container"
499
- this.appendChild(label);
500
- this.appendChild(pillDiv);
501
-
502
- let dTriggerElem = document.createElement('button');
503
- if (this._state.adPills.length > 0) {
504
-
505
- for (let i = 0; i < this._state.adPills.length; i++) {
506
-
507
- pillDiv.append(this._state.adPills[i])
508
- const customEvent = new CustomEvent('pill-created', { detail: { pill: this._state.adPills[i] } });
509
- this.dispatchEvent(customEvent);
510
- this._state.adPills[i].addEventListener('pill_removed', (e) => {
511
- let removedValue = e.detail.state.sValue1;
512
- // Find the index of the item in _initialState
513
- const initialIndex = this._initialState.configData.filterCriteria.items.findIndex(item => item.value === removedValue);
514
-
515
-
516
- // Check if the item is already in criteriaList
517
- if (!this._state.criteriaList.some(item => item.value === removedValue)) {
518
- // Find the item in configData.filterCriteria.items
519
- const itemToAdd = this._state.configData.filterCriteria.items.find(item => item.value === removedValue);
520
- if (itemToAdd) {
521
- // Insert the item at the same position as in _initialState
522
- if (initialIndex !== -1) {
523
- this._state.criteriaList.splice(initialIndex, 0, itemToAdd);
524
- } else {
525
- // If the item is not found in _initialState, default to adding at the end
526
- this._state.criteriaList.push(itemToAdd);
527
- }
528
- }
529
- }
530
-
531
-
532
- const myEvent = new CustomEvent("pill-removed", {
533
- detail: { pill: e.detail }
534
- });
535
- let index = this._state.adPills.findIndex(item => item._state == e.detail.state);
536
-
537
- if (index > 0) {
538
- this._state.adPills.splice(index, 1);
539
-
540
- } else if (index === 0) {
541
- this._state.adPills = [];
542
- }
543
- this.dispatchEvent(myEvent);
544
- });
545
- this.querySelectorAll('.pill-title')[pillDiv.children.length - 1].addEventListener('click', (e) => {
546
- this.menuTriggerOnClick(e.target.closest("cui-formpill-pill"));
547
- });
548
- }
549
-
550
- }
551
-
552
- dTriggerElem.title = this._state.sLabel;
553
- dTriggerElem.setAttribute('aria-label', this._state.sLabel);
554
-
555
- if (this._state.bAccessibleHideLabel) {
556
- dTriggerElem.textContent = "";
557
- label.textContent = "";
558
- } else {
559
- dTriggerElem.textContent = this._state.sLabel;
560
- label.textContent = this._state.sLabel + ':';
561
- }
562
-
563
- dTriggerElem.setAttribute('aria-controls', 'menu2');
564
- dTriggerElem.setAttribute('aria-haspopup', 'true');
565
- dTriggerElem.classList.add("button-menu-trigger");
566
- dTriggerElem.part = "menu-trigger"
567
- dTriggerElem.slot = "menu-trigger";
568
- dTriggerElem.type = "button";
569
- dTriggerElem.addEventListener('click', async (event) => {
570
- this.menuTriggerOnClick();
571
- });
572
-
573
- if (this._state.sIconBasePath) {
574
- let icon = document.createElement('cui-icon');
575
- icon.setAttribute("src", this._state.sIconBasePath)
576
- icon.classList.add('accessibleHideLabel')
577
- dTriggerElem.prepend(icon);
578
- } else {
579
- let addIconDiv = document.createElement('div');
580
- addIconDiv.textContent = '+';
581
- addIconDiv.classList.add('add-icon');
582
- addIconDiv.part = 'add-icon';
583
- dTriggerElem.prepend(addIconDiv);
584
- }
585
-
586
- this.dTriggerElem = dTriggerElem;
587
- this.appendChild(this.dTriggerElem);
588
-
589
- window.addEventListener('resize', (e) => {
590
- this.windowResize(e);
591
- window.removeEventListener('resize', this.windowResize())
592
- });
593
-
594
-
595
438
  }
596
439
 
597
- menuTriggerOnClick(formpill = null) {
440
+ menuTriggerOnClick(dFormPill = null) {
598
441
  if (this._state.bMenuDisplayed) {
599
442
  this.hidePopover();
600
- } else if (formpill !== null) {
601
- this.displayPillPopover(formpill);
602
- }
603
- else {
604
- this.displayPopover(); 1
443
+ } else {
444
+ this.displayPopover(dFormPill);
605
445
  }
606
446
  }
607
447
 
608
448
  globalBodyClick(evt) {
609
- if (this._state.dMenuPopover && !this._state.dMenuPopover.contains(evt.target)) {
449
+ if (!this.contains(evt.target) && this._state.dMenuPopover && !this._state.dMenuPopover.contains(evt.target)) {
610
450
  this.hidePopover();
611
451
  }
612
452
  }
613
453
 
614
- async createPopover(dTriggerElem, isPillPopover = false) {
615
- if (this._state.bMenuDisplayed == true) {
616
- return;
617
- }
454
+ displayPopover(dFormPill = null) {
618
455
 
619
- this._state.bMenuDisplayed = true;
456
+ let dDefaultControl = document.createElement('cui-listbox')
457
+ dDefaultControl.setAttribute('label', 'Criteria');
458
+ dDefaultControl.setAttribute('required', 'true');
459
+ dDefaultControl.setAttribute('componentKey', 'critiria');
620
460
 
621
- let dMenuPopover = document.createElement('cui-formpill-popover');
622
- if (!this.bMobile) {
623
- dMenuPopover.classList.add("button-menu");
624
- }
461
+ this.dDefaultControl = dDefaultControl;
625
462
 
626
- dMenuPopover.zIndex = 900;
627
- dMenuPopover.for = dTriggerElem;
628
- dMenuPopover.appendLocation = document.body;
629
- dMenuPopover.includeArrow = true;
463
+ //Create dom based on the config Data
464
+ if (this._state.aoConfig?.items?.length) {
465
+ let aOptions = [];
466
+ for (let options of this._state.aoConfig.items) {
467
+ aOptions.push({ 'label': options.label, 'value': options.value })
468
+ }
630
469
 
631
- this._state.dMenuPopover = dMenuPopover;
632
- this._state.dMenuPopover.state.sPosition = this._state.sPosition;
633
- this._state.dMenuPopover.state.bOpen = true;
634
- let dPopoverContent = null;
635
- if (this.bMobile) {
636
- dPopoverContent = document.createElement('dialog');
637
- dPopoverContent.classList.add('dialog-popover-contents');
470
+ let dItems = this.convertOptionsToChildElemsDOM(aOptions, dFormPill);
471
+ dDefaultControl.append(...dItems.childNodes)
638
472
 
639
- } else {
640
- dPopoverContent = document.createElement('div');
641
- dPopoverContent.classList.add('popover-contents');
473
+ dDefaultControl.addEventListener('change', this.generateBodyContent.bind(this))
642
474
  }
643
475
 
644
- dPopoverContent.slot = "popover-contents";
645
- dPopoverContent.classList.add('popover-contents');
646
- let dPopoverBody = document.createElement('div');
647
- dPopoverBody.classList.add("popover-body");
476
+ if (dFormPill) {
477
+ let oPopoverContents = this.renderPopover(dDefaultControl, true, dFormPill)
648
478
 
649
- let dPopoverHeader = document.createElement('div')
650
- dPopoverHeader.classList.add('popover-header')
651
-
652
- let dPopoverTitle = document.createElement('h3');
653
-
654
- dPopoverHeader.appendChild(dPopoverTitle);
655
-
656
- let closeButton = document.createElement('button');
657
- closeButton.classList.add('close-button');
658
- closeButton.textContent = '×'
659
- dPopoverHeader.appendChild(closeButton);
660
- closeButton.addEventListener('click', () => { this.hidePopover() })
661
-
662
- let dPopoverFooter = document.createElement('div');
663
- dPopoverFooter.classList.add("popover-footer");
479
+ //Set exisiting criteria value and make it readOnly
480
+ if (dDefaultControl.setState) {
481
+ dDefaultControl.setState({ readOnly: true, value: dFormPill.contents.value })
482
+ } else {
483
+ dDefaultControl.setAttribute('readOnly', true);
484
+ dDefaultControl.setAttribute('value', dFormPill.contents.value);
485
+ }
664
486
 
665
- if (isPillPopover === true) {
666
- dPopoverTitle.textContent = this._state.sUpdateTitle;
667
- dPopoverFooter.innerHTML = this.pillFooter
487
+ //Set exisiting values if they exist in the pill
488
+ if (dFormPill?.contents?.fields) {
489
+ this.setExistingFieldValues(dFormPill.contents.fields, oPopoverContents, true)
490
+ }
668
491
  } else {
669
- dPopoverTitle.textContent = this._state.sAddTitle;
670
- dPopoverFooter.innerHTML = this.footer
492
+ this.renderPopover(dDefaultControl)
671
493
  }
672
494
 
673
- let closeBtn = null;
674
- if (this.bMobile) {
675
-
676
- closeBtn = document.createElement('button');
677
- closeBtn.classList.add('dialog-close');
678
- closeBtn.setAttribute('id', 'dialog-close');
679
- closeBtn.part = 'dialog-close';
680
- let span = document.createElement('span');
681
- span.part = 'dialog-close-span';
682
- span.innerHTML = `&#215;`
683
- closeBtn.appendChild(span)
684
- let header = document.createElement('header');
685
- header.appendChild(closeBtn)
686
-
687
- dPopoverBody.appendChild(header)
688
- }
689
-
690
- dPopoverContent.addEventListener(
691
- "eventAction",
692
- (e) => {
693
-
694
- if (e.target != this) {
695
-
696
- e.stopImmediatePropagation();
697
-
698
- let eventDetail = e.detail;
699
- eventDetail.target = this;
700
-
701
- // //target to detail
702
-
703
- const E_CONTROL_EVENT = new CustomEvent("eventAction", {
704
- bubbles: true,
705
- composed: true,
706
- detail: eventDetail
707
- });
708
-
709
- this.dispatchEvent(E_CONTROL_EVENT);
710
- }
711
-
712
- },
713
- false
714
- );
715
-
716
- dPopoverBody.appendChild(dPopoverHeader)
717
- dPopoverBody.appendChild(dPopoverFooter);
718
- dPopoverContent.appendChild(dPopoverBody);
719
- dMenuPopover.appendChild(dPopoverContent);
720
-
721
- return [dPopoverBody, dPopoverContent, dMenuPopover, dPopoverFooter]
722
495
  }
723
496
 
724
- async displayPopover() {
725
-
726
- let adPopoverElements = await this.createPopover(this.dTriggerElem);
727
- let dPopoverBody = adPopoverElements[0];
728
- let dPopoverContent = adPopoverElements[1];
729
- let dMenuPopover = adPopoverElements[2];
730
- let dPopoverFooter = adPopoverElements[3];
497
+ generateBodyContent(evt) {
498
+ let controls = document.createElement('div');
731
499
 
732
-
733
- this.criteria = null;
734
- this.method = null;
735
- this.dValueField = null;
736
- this.field = null;
737
- this.adFields = [];
738
-
739
- if (this._state.configData) {
740
- if (this._state.configData.filterCriteria) {
741
- this.criteria = document.createElement('cui-listbox');
742
- this.criteria.setAttribute('search', '');
743
- let items = []
744
-
745
- if (this._state.criteriaList === null) {
746
- for (let item of this._state.configData.filterCriteria.items) {
747
- let lbValue = { 'label': item.label, 'value': item.value };
748
- if (item.multiple) {
749
- lbValue.multiple = item.multiple
500
+ for (let item of this._state.aoConfig.items) {
501
+ if (item.value === evt.detail.data.value) {
502
+ let aoControls;
503
+ if (item?.template) {
504
+ if (Object.hasOwn(this._state.aoConfig.templates, item.template)) {
505
+ if (this._state.aoConfig.templates[item.template]?.controls) {
506
+ aoControls = this._state.aoConfig.templates[item.template].controls
750
507
  }
751
- items.push(lbValue);
752
- }
753
- this._state.criteriaList = items;
754
- } else {
755
- for (let item of this._state.criteriaList) {
756
- items.push(item);
757
508
  }
758
509
  }
510
+ else if (item?.controls?.length) {
511
+ aoControls = item.controls
512
+ }
759
513
 
760
- this.criteria.setState({ 'items': items, 'label': `${(this._state.configData.filterCriteria.fieldLabel) ? this._state.configData.filterCriteria.fieldLabel : 'Criteria'}` })
761
- this.criteria.setAttribute('required', '');
762
- this.criteria.setAttribute('componentKey', 'contextHeaderCriteria');
763
- dPopoverBody.insertBefore(this.criteria, dPopoverFooter)
764
-
765
- this.handleCriteriaChange(dPopoverBody, dPopoverFooter)
766
-
514
+ if (aoControls.length) {
515
+ let controld;
516
+ for (const control of aoControls) {
517
+ controld = this.convertJsonToDom(control);
518
+ controls.appendChild(controld)
519
+ }
520
+ }
767
521
  }
768
- let dAddButton = dPopoverBody.querySelector('.addBtn');
769
- this.handleAddUpdate(dAddButton, dPopoverBody, 'add')
770
-
771
- dPopoverBody.querySelector('.resetBtn').addEventListener('click', (e) => {
772
- this.criteria.setState({ 'value': '' })
773
- this.criteria.messages.removeAll();
774
- })
775
-
776
522
  }
777
523
 
778
- window.requestAnimationFrame(() => {
779
- dMenuPopover.append();
780
- if (this.bMobile) {
781
- dPopoverContent.showModal()
782
- closeBtn.addEventListener('click', (e) => {
783
- dPopoverContent.close();
784
- this.hidePopover();
785
- })
786
- }
787
- document.body.addEventListener('click', this.fGlobalBodyClick, false);
788
- });
524
+ let dBody = this._state.dMenuPopover.querySelector('.body-content');
525
+ dBody.replaceChildren(...controls.childNodes)
789
526
 
527
+ let customEvent = new CustomEvent('filter-change', { detail: evt.detail });
528
+ this.dispatchEvent(customEvent);
790
529
 
791
530
  }
792
531
 
793
- async displayPillPopover(pill) {
794
-
795
- let adPopoverElements = await this.createPopover(pill, true);
796
- let dPopoverBody = adPopoverElements[0];
797
- let dPopoverContent = adPopoverElements[1];
798
- let dMenuPopover = adPopoverElements[2];
799
- let dPopoverFooter = adPopoverElements[3];
800
-
801
- this.criteria = null;
802
- this.method = null;
803
- this.dValueField = null;
804
- this.field = null;
805
- this.adFields = [];
806
- if (this._state.configData) {
807
- if (this._state.configData.filterCriteria) {
808
- this.criteria = document.createElement('cui-listbox');
809
- let items = []
810
-
811
- for (let item of this._state.configData.filterCriteria.items) {
812
- let lbValue = { 'label': item.label, 'value': item.value };
813
- items.push(lbValue);
814
- }
532
+ setExistingFieldValues(oFields, oPopoverContents, initialLoad = false) {
533
+ let dFields = oPopoverContents?.dBody?.children;
815
534
 
816
- this.criteria.setState({ 'items': items, 'label': `${(this._state.configData.filterCriteria.fieldLabel) ? this._state.configData.filterCriteria.fieldLabel : 'Criteria'}` })
817
- this.criteria.setAttribute('value', pill._state.sValue1)
818
- this.criteria.setAttribute('required', '');
819
- this.criteria.setAttribute('readOnly', '');
820
- this.criteria.setAttribute('componentKey', 'contextHeaderCriteria');
821
- dPopoverBody.insertBefore(this.criteria, dPopoverFooter)
535
+ //If Update, assign existing values to the fields if they exists
536
+ for (let field of dFields) {
822
537
 
823
- this.handleCriteriaChange(dPopoverBody, dPopoverFooter, pill, true)
538
+ let sPreferredKey = this.retrievePreferredKey(field);
824
539
 
540
+ if (sPreferredKey && oFields?.[sPreferredKey]) {
541
+ if (field.setState) {
542
+ field.setState({ value: oFields[sPreferredKey] }, initialLoad)
543
+ } else {
544
+ field.setAttribute('value', oFields[sPreferredKey])
545
+ }
825
546
  }
826
547
  }
827
- let formPill = dMenuPopover.state.dFor;
828
- let dUpdateButton = dPopoverBody.querySelector('.updateBtn');
829
- this.handleAddUpdate(dUpdateButton, dPopoverBody, 'update', formPill)
830
-
831
- dPopoverBody.querySelector('.resetBtn').addEventListener('click', (e) => {
832
- this.hidePopover();
833
- this.menuTriggerOnClick(formPill);
834
- })
835
-
836
- window.requestAnimationFrame(() => {
837
- dMenuPopover.append();
838
- if (this.bMobile) {
839
- dPopoverContent.showModal()
840
- closeBtn.addEventListener('click', (e) => {
841
- dPopoverContent.close();
842
- this.hidePopover();
843
- })
844
- }
845
- document.body.addEventListener('click', this.fGlobalBodyClick, false);
846
- });
847
-
548
+ }
848
549
 
550
+ retrievePreferredKey(dField) {
551
+ return (
552
+ dField.getAttribute('propertyKey') ||
553
+ dField.getAttribute('componentKey') ||
554
+ dField.getAttribute('id') ||
555
+ null
556
+ );
849
557
  }
850
558
 
851
- handleCriteriaChange(dPopoverBody, dPopoverFooter, pill = null, isPill = false) {
852
- let selectedValue;
559
+ renderPopover(dBodyContent, forPill = false, dFormPill) {
560
+ if (this._state.bMenuDisplayed == true) return;
853
561
 
854
- if (pill && isPill) {
855
- selectedValue = pill._state.sValue1;
856
- let selectedItem = this._state.configData.filterCriteria.items.find(item => item.value === selectedValue);
562
+ let sLayout = this.sPopoverLayout(forPill);
857
563
 
858
- let controls = selectedItem.controls;
859
- if (controls.options && controls.value) {
564
+ let dContainer = document.createElement('div');
565
+ dContainer.innerHTML = sLayout;
860
566
 
861
- this.method = document.createElement('cui-listbox');
862
- if (controls.search) this.method.setAttribute('search', '');
863
- this.method.setState({ 'items': controls.options, 'label': `${(controls.fieldLabel) ? controls.fieldLabel : 'Method'}` });
864
- this.method.setAttribute('value', pill._state.sValue2)
865
- this.method.setAttribute('required', '');
866
- this.method.setAttribute('componentKey', 'contextHeaderMethod');
867
- dPopoverBody.insertBefore(this.method, dPopoverFooter);
567
+ // Append to DOM
568
+ let dPopover = dContainer.firstElementChild;
569
+ dPopover.for = dFormPill ?? this.dTrigger;
570
+ this._state.dMenuPopover = dPopover
868
571
 
869
- if (controls.value.control === 'text') {
870
- this.dValueField = document.createElement('cui-text');
871
- }
872
- if (controls.value.control === 'date') {
873
- this.dValueField = document.createElement('cui-date');
874
- }
572
+ let dContent = dPopover.querySelector('[slot="popover-contents"]')
875
573
 
876
- if (controls.value.validation) {
877
- this.dValueField.setAttribute('validation', controls.value.validation);
878
- }
879
-
880
- this.dValueField.setState({ 'label': `${(controls.value.fieldLabel) ? controls.value.fieldLabel : 'Value'}` })
881
- this.dValueField.setAttribute('value', pill._state.sValue3)
882
- this.dValueField.setAttribute('required', '');
883
- this.dValueField.setAttribute('componentKey', 'contextHeaderValue');
884
- dPopoverBody.insertBefore(this.dValueField, dPopoverFooter);
574
+ dContent.addEventListener("eventAction", (e) => {
885
575
 
886
- } else if (controls.value && controls.value.options) {
887
- this.dValueField = document.createElement('cui-listbox');
888
- this.dValueField.setState({ 'items': controls.value.options, 'label': `${(controls.fieldLabel) ? controls.fieldLabel : 'Value'}` });
576
+ if (e.target != this) {
889
577
 
578
+ e.stopImmediatePropagation();
890
579
 
891
- if (controls.value.multiple) {
892
- this.dValueField.setAttribute('multiple', true)
893
- }
894
- if (controls.value.codedesc) {
895
- this.dValueField.setAttribute('codedesc', true)
896
- }
897
- if (controls.value.search) {
898
- this.dValueField.setAttribute('search', true)
899
- }
900
- if (pill?._state?.sValue2) {
901
- if (pill._state.sValue2.indexOf(',') == -1) {
902
- this.dValueField.setAttribute('value', pill._state.sValue2)
903
- }
904
- else {
580
+ let eventDetail = e.detail;
581
+ eventDetail.targetPopover = dPopover;
582
+ eventDetail.target = this;
583
+ const E_CONTROL_EVENT = new CustomEvent("eventAction", {
584
+ bubbles: true,
585
+ composed: true,
586
+ detail: eventDetail
587
+ });
905
588
 
906
- let aValues = pill._state.sValue2.split(',');
907
- this.dValueField.setAttribute('value', aValues)
908
- }
909
- }
589
+ this.dispatchEvent(E_CONTROL_EVENT);
590
+ }
910
591
 
911
- if (pill?._state?.asValues) {
912
- let aValues = pill._state.asValues.split(',');
913
- this.dValueField.setAttribute('value', aValues)
914
- }
592
+ }, false);
915
593
 
594
+ //assign reemit for the relay events
595
+ if (this._state.aoConfig?.relayEvents?.length) {
596
+ this.relayEvents(this._state.aoConfig.relayEvents, dContent)
597
+ }
916
598
 
917
- this.dValueField.setAttribute('required', '');
918
- this.dValueField.setAttribute('componentKey', 'contextHeaderValue');
919
- dPopoverBody.insertBefore(this.dValueField, dPopoverFooter);
920
- } else if (controls.value && controls.value.control) {
599
+ let dBody = dPopover.querySelector('.body-content');
600
+ let dPopoverBody = dPopover.querySelector('.popover-body');
601
+ dPopoverBody.insertBefore(dBodyContent, dBody)
921
602
 
922
- for (let i = 0; i < controls.value.control.length; i++) {
603
+ document.body.appendChild(dPopover);
923
604
 
924
- if (controls.value.control[i].type === "text") {
925
- this.field = document.createElement('cui-text');
605
+ if (this.bMobile) {
606
+ dContent.showModal();
607
+ }
926
608
 
927
- } else if (controls.value.control[i].type === "date") {
928
- this.field = document.createElement('cui-date');
929
- }
609
+ if (forPill) {
610
+ let dAddButton = dPopoverBody.querySelector('.updateBtn');
611
+ dAddButton.addEventListener('click', this.addUpdatePill(dFormPill));
930
612
 
931
- this.field.setState({ 'label': controls.value.control[i].label })
932
- if (controls.value.control[i].required) {
933
- this.field.setAttribute('required', '');
934
- }
613
+ // Add Reset listener
614
+ let dResetButton = dPopoverBody.querySelector('.resetBtn');
615
+ dResetButton.addEventListener('click', function () {
616
+ // Query all relevant elements
617
+ const keys = ['propertyKey', 'componentKey', 'id'];
618
+ const selector = keys.map(attr => `[${attr}]`).join(', ');
619
+ const elements = dBody.querySelectorAll(selector);
935
620
 
936
- if (controls.value.control[i].validation) {
937
- this.field.setAttribute('validation', controls.value.control[i].validation)
621
+ // Reset each element if it has a reset method
622
+ elements.forEach(element => {
623
+ if (typeof element.reset === 'function') {
624
+ element.reset();
938
625
  }
626
+ });
627
+ }.bind(this));
939
628
 
940
- this.field.setAttribute('componentKey', controls.value.control[i].componentKey);
941
- dPopoverBody.insertBefore(this.field, dPopoverFooter);
942
- this.adFields.push(this.field);
943
-
944
- }
945
- let pillValues = pill._state.asValues.split(',');
946
- for (let i = 0; i < pillValues.length; i++) {
947
- this.adFields[i].setAttribute('value', pillValues[i])
948
-
949
- }
950
- }
951
-
952
- const customEvent = new CustomEvent('filter-change', { detail: { value: selectedItem.value, label: selectedItem.label } });
953
- this.dispatchEvent(customEvent);
954
629
  } else {
955
630
 
631
+ let dAddButton = dPopoverBody.querySelector('.addBtn');
632
+ dAddButton.addEventListener('click', this.addUpdatePill());
956
633
 
957
- this.criteria.addEventListener('change', (e) => {
958
-
959
- const customEvent = new CustomEvent('filter-change', { detail: { value: this.criteria.value, label: this.criteria.label } });
960
- this.dispatchEvent(customEvent);
961
-
962
- let removeCriteriaSiblings = function (element) {
963
- Array.from(element.parentNode.children).filter(sibling => sibling !== element && (sibling.tagName.toLowerCase() === 'cui-listbox' || sibling.tagName.toLowerCase() === 'cui-text' || sibling.tagName.toLowerCase() === 'cui-date')).forEach(sibling => sibling.remove());
964
- };
965
- removeCriteriaSiblings(this.criteria);
966
-
967
- selectedValue = e.detail.data.value;
968
- let selectedItem = this._state.configData.filterCriteria.items.find(item => item.value === selectedValue);
969
- if (selectedItem) {
970
- let controls = selectedItem.controls;
971
-
972
- if (controls.options && controls.value) {
973
-
974
- this.method = document.createElement('cui-listbox');
975
- if (controls.search) this.method.setAttribute("search", "");
976
- this.method.setState({ 'items': controls.options, 'label': `${(controls.fieldLabel) ? controls.fieldLabel : 'Method'}` });
977
- this.method.setAttribute('required', '');
978
- this.method.setAttribute('componentKey', 'contextHeaderMethod');
979
- dPopoverBody.insertBefore(this.method, dPopoverFooter);
980
-
981
- if (controls.value.control === 'text') {
982
- this.dValueField = document.createElement('cui-text');
983
- this.dValueField.setState({ 'label': `${(controls.value.fieldLabel) ? controls.value.fieldLabel : 'Value'}` })
984
- this.dValueField.setAttribute('required', '');
985
- this.dValueField.setAttribute('componentKey', 'contextHeaderValue');
986
- dPopoverBody.insertBefore(this.dValueField, dPopoverFooter);
987
- }
988
- if (controls.value.validation) {
989
- this.dValueField.setAttribute('validation', controls.value.validation);
990
- }
991
-
992
- } else if (controls.value && controls.value.options) {
993
- this.dValueField = document.createElement('cui-listbox');
994
- this.dValueField.setState({ 'items': controls.value.options, 'label': `${(controls.fieldLabel) ? controls.fieldLabel : 'Value'}` });
995
- this.dValueField.setAttribute('required', '');
996
- this.dValueField.setAttribute('componentKey', 'contextHeaderValue');
997
- if (controls.value.multiple) {
998
- this.dValueField.setAttribute('multiple', true)
999
- }
1000
- if (controls.value.codedesc) {
1001
- this.dValueField.setAttribute('codedesc', true)
1002
- }
1003
- if (controls.value.search) {
1004
- this.dValueField.setAttribute('search', true)
1005
- }
1006
- dPopoverBody.insertBefore(this.dValueField, dPopoverFooter);
1007
- } else if (controls.value && controls.value.control) {
1008
-
1009
- for (let i = 0; i < controls.value.control.length; i++) {
1010
- if (controls.value.control[i].type === "text") {
1011
- this.field = document.createElement('cui-text');
1012
-
1013
- } else if (controls.value.control[i].type === "date") {
1014
- this.field = document.createElement('cui-date');
1015
- }
1016
-
1017
- if (controls.value.control[i].validation) {
1018
- this.field.setAttribute('validation', controls.value.control[i].validation)
1019
- }
1020
-
1021
- this.field.setState({ 'label': controls.value.control[i].label })
1022
- if (controls.value.control[i].required) {
1023
- this.field.setAttribute('required', '');
1024
- }
1025
- this.field.setAttribute('componentKey', controls.value.control[i].componentKey);
1026
- dPopoverBody.insertBefore(this.field, dPopoverFooter);
1027
- this.adFields.push(this.field);
1028
-
1029
- }
1030
- }
1031
- } else {
1032
- console.log("No item found with the selected value.");
1033
- }
1034
- })
634
+ let dResetButton = dPopoverBody.querySelector('.resetBtn');
635
+ dResetButton.addEventListener('click', function () {
636
+ this.dDefaultControl.setState({ "value": "" })
637
+ }.bind(this));
1035
638
  }
1036
639
 
1037
- }
640
+ let closeBtn = dPopoverBody.querySelector('.close-button');
641
+ closeBtn.addEventListener('click', function () {
642
+ this.hidePopover();
643
+ }.bind(this));
1038
644
 
1039
- handleAddUpdate(dButton, dPopoverBody, sFor, pill = null) {
1040
- dButton.addEventListener('click', (e) => {
1041
- let validatedFields = this.validateRegion(dPopoverBody);
645
+ this._state.bMenuDisplayed = true;
1042
646
 
1043
- if (validatedFields) {
1044
- let formPill;
1045
- if (sFor === 'add') {
1046
- formPill = document.createElement('cui-formpill-pill');
1047
- this._state.adPills.push(formPill);
1048
- } else {
1049
- formPill = pill;
1050
- }
647
+ document.body.addEventListener('click', this.fGlobalBodyClick, false);
1051
648
 
1052
- if (this.method !== null && this.dValueField !== null) {
1053
- let curValue = this.criteria.value;
1054
- formPill.setAttribute('value1', this.criteria.value)
1055
- formPill.setAttribute('value2', this.method.value)
1056
- formPill.setAttribute('value3', this.dValueField.value)
1057
- let pillText = `${this.criteria._state.aItems.find(item => item.value === this.criteria.value)?.label}: ${this.dValueField.value}`
1058
- if (sFor === 'update') {
1059
- formPill.setState({
1060
- 'value1': this.criteria.value, 'value2': this.method.value, 'value3': this.dValueField.value,
1061
- 'text': `${this.criteria._state.aItems.find(item => item.value === this.criteria.value)?.label}: ${this.dValueField.value}`
1062
- })
1063
- }
1064
- formPill.setAttribute('text', pillText.slice(0, 30) + (pillText.length > 30 ? "..." : ""))
1065
-
1066
- if (sFor === 'add') {
1067
- let updatedList = this._state.criteriaList.filter(item => {
1068
- if (item.multiple) {
1069
- return true;
1070
- }
1071
- return item.value !== curValue;
1072
- });
1073
-
1074
- this._state.criteriaList = updatedList;
1075
-
1076
- formPill.addEventListener('pill_removed', (e) => {
1077
- let removedValue = e.detail.state.sValue1;
1078
- // Find the index of the item in _initialState
1079
- const initialIndex = this._initialState.configData.filterCriteria.items.findIndex(item => item.value === removedValue);
1080
-
1081
-
1082
- // Check if the item is already in criteriaList
1083
- if (!this._state.criteriaList.some(item => item.value === removedValue)) {
1084
- // Find the item in configData.filterCriteria.items
1085
- const itemToAdd = this._state.configData.filterCriteria.items.find(item => item.value === removedValue);
1086
- if (itemToAdd) {
1087
- // Insert the item at the same position as in _initialState
1088
- if (initialIndex !== -1) {
1089
- this._state.criteriaList.splice(initialIndex, 0, itemToAdd);
1090
- } else {
1091
- // If the item is not found in _initialState, default to adding at the end
1092
- this._state.criteriaList.push(itemToAdd);
1093
- }
1094
- }
1095
- }
649
+ return { 'dPopoverBody': dPopoverBody, 'dBody': dBody, 'dPopover': dPopover }
650
+ }
1096
651
 
652
+ addUpdatePill(dFormPill = null) {
653
+ return function (e) {
1097
654
 
655
+ let dPopoverBody = e.target.closest('.popover-body')
656
+ let bVlaidateFields = this.validateRegion(dPopoverBody);
657
+
658
+ if (bVlaidateFields) {
659
+ let dCriteria = dPopoverBody.querySelector('cui-listbox');
660
+
661
+ //Find Lable in the lIstbox item else null
662
+ let sCriteriaLabel = (dCriteria.item.find(item => item.value === dCriteria.value) || {}).label
663
+ let sCriteriaValue = dCriteria.value;
1098
664
 
665
+ let dFields = dPopoverBody.querySelector('.body-content').children;
1099
666
 
667
+ let sCriteriaValueLabel = "";
1100
668
 
669
+ let oFields = {};
1101
670
 
671
+ for (const field of dFields) {
1102
672
 
1103
- const myEvent = new CustomEvent("pill-removed", {
1104
- detail: { pill: e.detail }
1105
- });
673
+ let sPreferredKey = this.retrievePreferredKey(field)
1106
674
 
1107
- let index = this._state.adPills.findIndex(item => item._state == e.detail.state);
675
+ if (sPreferredKey) {
676
+ if (field.hasAttribute('pillValue')) {
677
+ if (sCriteriaValueLabel) sCriteriaValueLabel += ", "
1108
678
 
1109
- //if(index > 0){
1110
- this._state.adPills.splice(index, 1);
679
+ //check if listbox
680
+ if (field.item && field.item.length) {
1111
681
 
1112
- //}else if(index === 0){
1113
- //this._state.adPills = [];
1114
- //}
682
+ let aValues = field.value.split(',').map(v => v.trim());
1115
683
 
1116
- this.dispatchEvent(myEvent);
1117
- });
1118
- }
684
+ let sLabel = aValues.map(sVal => {
685
+ let oItem = field.item.find(oItem => oItem.value === sVal);
686
+ return (oItem && oItem.label) || sVal;
687
+ });
1119
688
 
1120
- if (sFor === 'update') {
1121
- const myEvent = new CustomEvent("pill-updated", {
1122
- detail: { pill: formPill }
1123
- });
1124
- this.dispatchEvent(myEvent);
689
+ sCriteriaValueLabel += sLabel;
690
+ } else {
691
+ sCriteriaValueLabel += field.value;
692
+ }
693
+ }
694
+ oFields[sPreferredKey] = field.value;
1125
695
  }
1126
696
 
1127
- } else if (this.dValueField !== null) {
697
+ }
1128
698
 
1129
- let curValue = this.criteria.value;
1130
- formPill.setAttribute('value1', curValue)
1131
- let pillText;
1132
- if (this.dValueField.value.indexOf(',') == -1) {
1133
- formPill.setAttribute('value2', this.dValueField.value)
1134
- pillText = `${this.criteria._state.aItems.find(item => item.value === this.criteria.value)?.label}: ${this.dValueField._state.aItems.find(item => item.value === this.dValueField.value)?.label}`
699
+ if (dFormPill) {
700
+ this.#updatePill(dFormPill, { "label": sCriteriaLabel, "value": sCriteriaValue, "valueLabel": sCriteriaValueLabel, "fields": oFields });
701
+ } else {
702
+ this.#createAndAppendPill({ "label": sCriteriaLabel, "value": sCriteriaValue, "valueLabel": sCriteriaValueLabel, "fields": oFields });
1135
703
 
1136
- }
1137
- else {
1138
- let aValues = this.dValueField.value.split(',');
1139
- formPill.setAttribute('value2', aValues)
704
+ }
1140
705
 
1141
- // Loop through each value in the array
1142
- const labels = aValues.map(val => {
1143
- // Find the corresponding label for each value
1144
- const item = this.dValueField._state.aItems.find(item => item.value === val);
1145
- return item?.label;
1146
- });
706
+ this.hidePopover();
1147
707
 
1148
- // Join the labels with a comma
1149
- pillText = `${this.criteria._state.aItems.find(item => item.value === this.criteria.value)?.label}: ${labels.join(', ')}`;
708
+ this._state.sCriteriaList.add(dCriteria.value)
709
+ }
1150
710
 
1151
- }
711
+ }.bind(this)
712
+ }
1152
713
 
1153
- if (sFor === 'update') {
1154
- formPill.setState({
1155
- 'value1': this.criteria.value, 'value2': this.dValueField.value,
1156
- 'text': pillText
1157
- });
1158
- }
714
+ #createAndAppendPill(oState, isOnRender = false) {
1159
715
 
1160
- formPill.setAttribute('text', pillText.slice(0, 30) + (pillText.length > 30 ? "..." : ""))
716
+ let dPill = document.createElement('cui-formpill-pill');
1161
717
 
1162
- if (sFor === 'add') {
1163
- let updatedList = this._state.criteriaList.filter(item => {
1164
- if (item.multiple) {
1165
- return true;
1166
- }
1167
- return item.value !== curValue;
1168
- });
1169
-
1170
- this._state.criteriaList = updatedList;
1171
-
1172
- formPill.addEventListener('pill_removed', (e) => {
1173
- let removedValue = e.detail.state.sValue1;
1174
- // Find the index of the item in _initialState
1175
- const initialIndex = this._initialState.configData.filterCriteria.items.findIndex(item => item.value === removedValue);
1176
-
1177
-
1178
- // Check if the item is already in criteriaList
1179
- if (!this._state.criteriaList.some(item => item.value === removedValue)) {
1180
- // Find the item in configData.filterCriteria.items
1181
- const itemToAdd = this._state.configData.filterCriteria.items.find(item => item.value === removedValue);
1182
- if (itemToAdd) {
1183
- // Insert the item at the same position as in _initialState
1184
- if (initialIndex !== -1) {
1185
- this._state.criteriaList.splice(initialIndex, 0, itemToAdd);
1186
- } else {
1187
- // If the item is not found in _initialState, default to adding at the end
1188
- this._state.criteriaList.push(itemToAdd);
1189
- }
1190
- }
1191
- }
1192
-
1193
-
1194
- const myEvent = new CustomEvent("pill-removed", {
1195
- detail: { pill: e.detail }
1196
- });
718
+ if (this._state.iCharLimit) {
719
+ oState.charLimit = this._state.iCharLimit;
720
+ }
1197
721
 
1198
- let index = this._state.adPills.findIndex(item => item._state == e.detail.state);
722
+ dPill.setState(oState);
1199
723
 
1200
- //if(index > 0){
1201
- this._state.adPills.splice(index, 1);
724
+ this.querySelector('.pill-container').append(dPill)
1202
725
 
1203
- //}else if(index === 0){
1204
- // this._state.adPills = [];
1205
- //}
1206
- this.dispatchEvent(myEvent);
1207
- });
726
+ oState.dPill = dPill;
1208
727
 
728
+ if (!isOnRender) {
729
+ if (!this._state.aoPills) {
730
+ this._state.aoPills = [{ ...oState }]
731
+ } else {
732
+ this._state.aoPills.push({ ...oState })
733
+ }
734
+ }
1209
735
 
1210
- }
736
+ this.#addClickEvtForPill(dPill);
737
+ this.#addRemoveEvt(dPill);
1211
738
 
1212
- if (sFor === 'update') {
1213
- const myEvent = new CustomEvent("pill-updated", {
1214
- detail: { pill: formPill }
1215
- });
1216
- this.dispatchEvent(myEvent);
1217
- }
1218
- } else if (this.adFields.length > 0) {
739
+ return dPill;
740
+ }
1219
741
 
1220
- let curValue = this.criteria.value;
1221
- let values = [];
1222
- for (let curField of this.adFields) {
1223
- values.push(curField.value)
1224
- }
742
+ #updatePill(dPill, oState) {
1225
743
 
1226
- formPill.setAttribute('value1', this.criteria.value)
1227
- formPill.setAttribute('values', values)
744
+ if (this._state.iCharLimit) {
745
+ oState.charLimit = this._state.iCharLimit;
746
+ }
1228
747
 
1229
- let sPillText = `${this.criteria._state.aItems.find(item => item.value === this.criteria.value)?.label}: ${values}`
748
+ dPill.setState(oState);
1230
749
 
1231
- if (sFor === 'update') {
1232
- formPill.setState({
1233
- 'value1': this.criteria.value, 'values': values.join(","),
1234
- 'text': `${this.criteria._state.aItems.find(item => item.value === this.criteria.value)?.label}: ${values.join(",")}`
1235
- });
1236
- }
1237
- formPill.setAttribute('text', sPillText.slice(0, 30) + (sPillText.length > 30 ? "..." : ""))
750
+ for (let pill of this._state.aoPills) {
751
+ if (dPill === pill.dPill) {
752
+ oState.dPill = dPill;
753
+ pill = { ...oState };
754
+ console.log(pill);
1238
755
 
1239
- if (sFor === 'add') {
1240
- let updatedList = this._state.criteriaList.filter(item => {
1241
- if (item.multiple) {
1242
- return true;
1243
- }
1244
- return item.value !== curValue;
1245
- });
1246
-
1247
- this._state.criteriaList = updatedList;
1248
-
1249
- formPill.addEventListener('pill_removed', (e) => {
1250
- let removedValue = e.detail.state.sValue1;
1251
- // Find the index of the item in _initialState
1252
- const initialIndex = this._initialState.configData.filterCriteria.items.findIndex(item => item.value === removedValue);
1253
-
1254
- // Check if the item is already in criteriaList
1255
- if (!this._state.criteriaList.some(item => item.value === removedValue)) {
1256
- // Find the item in configData.filterCriteria.items
1257
- const itemToAdd = this._state.configData.filterCriteria.items.find(item => item.value === removedValue);
1258
- if (itemToAdd) {
1259
- // Insert the item at the same position as in _initialState
1260
- if (initialIndex !== -1) {
1261
- this._state.criteriaList.splice(initialIndex, 0, itemToAdd);
1262
- } else {
1263
- // If the item is not found in _initialState, default to adding at the end
1264
- this._state.criteriaList.push(itemToAdd);
1265
- }
1266
- }
1267
- }
756
+ }
757
+ }
1268
758
 
759
+ this.#addClickEvtForPill(dPill);
1269
760
 
1270
- const myEvent = new CustomEvent("pill-removed", {
1271
- detail: { pill: e.detail }
1272
- });
1273
- let index = this._state.adPills.findIndex(item => item._state == e.detail.state);
761
+ return dPill;
762
+ }
1274
763
 
1275
- //if(index > 0){
1276
- this._state.adPills.splice(index, 1);
764
+ #addClickEvtForPill(dPill) {
765
+ dPill.querySelector('.pill-title').addEventListener('click', () => {
766
+ this.menuTriggerOnClick(dPill);
767
+ });
768
+ }
1277
769
 
1278
- //}else if(index === 0){
1279
- //this._state.adPills = [];
1280
- //}
770
+ #addRemoveEvt(dPill) {
771
+ // pill_removed
772
+ dPill.addEventListener('pill_removed', (e) => {
773
+ //Updated criteria list and reemit the event
1281
774
 
1282
- this.dispatchEvent(myEvent);
1283
- });
1284
- }
775
+ if (this._state.sCriteriaList.has(e.detail.state.sValue)) {
776
+ this._state.sCriteriaList.delete(e.detail.state.sValue);
1285
777
 
1286
- if (sFor === 'update') {
1287
- const myEvent = new CustomEvent("pill-updated", {
1288
- detail: { pill: formPill }
1289
- });
1290
- this.dispatchEvent(myEvent);
778
+ for (let i = 0; i < this._state.aoPills.length; i++) {
779
+ let pill = this._state.aoPills[i];
780
+ if (pill.dPill === dPill) {
781
+ this._state.aoPills.splice(i, 1);
782
+ break; // Exit the loop after deleting
1291
783
  }
1292
784
  }
1293
-
1294
-
1295
- this.querySelector('.pill-container').append(formPill);
1296
-
1297
- if (sFor === 'add') {
1298
- const customEvent = new CustomEvent('pill-created', { detail: { pill: formPill } });
1299
- this.dispatchEvent(customEvent);
1300
-
1301
- }
1302
-
1303
-
1304
- formPill.querySelector('.pill-title').addEventListener('click', (e) => {
1305
- this.menuTriggerOnClick(formPill);
1306
- });
1307
-
1308
- this.hidePopover();
1309
785
  }
1310
- })
1311
786
 
787
+ })
1312
788
  }
1313
789
 
1314
- addPillfromJSON() {
1315
- if (this._state?.configData?.filterCriteria?.loadedPills) {
1316
- for (let pill of this._state.configData.filterCriteria?.loadedPills) {
1317
- let formPill;
1318
- formPill = document.createElement('cui-formpill-pill');
1319
- this._state.adPills.push(formPill);
790
+ convertOptionsToChildElemsDOM(aOptions, dPill = null) {
1320
791
 
1321
- for (const [k, v] of Object.entries(pill)) {
1322
- formPill.setAttribute(k, v);
1323
- }
1324
- // 'text': `${this.criteria._state.aItems.find(item => item.value === this.criteria.value)?.label}: ${this.dValueField.value}`
1325
- let pillText;
1326
-
1327
- if (pill.value2 != null && pill.value3 != null) {
1328
- pillText = `${this._state.configData.filterCriteria.items.find(item => item.value === pill.value1)?.label}: ${pill.value3}`
1329
- } else if (pill.values != null) {
1330
- const foundItem = this._state.configData.filterCriteria.items.find(item => item.value === pill.value1);
1331
- if (foundItem) {
1332
- const labelsArray = [];
1333
-
1334
- // Loop through each value in pill.values
1335
- for (const val of pill.values) {
1336
- const option = foundItem.controls.value.options.find(opt => opt.value === val);
1337
- if (option) {
1338
- labelsArray.push(option.label);
1339
- } else {
1340
- // If label not found, use the original value
1341
- labelsArray.push(val);
1342
- }
1343
- }
1344
-
1345
- // Join the labels with commas
1346
- const labelsString = labelsArray.join(', ');
792
+ let dContainer = document.createElement('div');
793
+ for (let options of aOptions) {
794
+ if (this._state.isMultiple || dPill?.state?.sValue === options.value || !this._state.sCriteriaList.has(options.value)) {
795
+ let item = document.createElement('cui-item')
796
+ item.setAttribute('label', options.label)
797
+ item.setAttribute('value', options.value)
798
+ dContainer.appendChild(item)
799
+ }
800
+ }
801
+ return dContainer;
802
+ }
1347
803
 
1348
- // Assign the label string to pillText
1349
- pillText = `${foundItem.label}: ${labelsString}`;
1350
- }
1351
- } else if (pill.value2 != null) {
1352
- const foundItem = this._state.configData.filterCriteria.items.find(item => item.value === pill.value1);
1353
- if (foundItem) {
1354
- // Split value2 by commas and trim whitespace
1355
- const values = pill.value2.split(',').map(v => v.trim());
1356
- const labelsArray = [];
1357
-
1358
- // Loop through each value and find its label in options
1359
- for (const val of values) {
1360
- const option = foundItem.controls.value.options.find(opt => opt.value === val);
1361
- if (option) {
1362
- labelsArray.push(option.label);
1363
- } else {
1364
- // If label not found, use the original value
1365
- labelsArray.push(val);
1366
- }
1367
- }
804
+ convertJsonToDom(controls) {
805
+ let dElement;
1368
806
 
1369
- // Join the found labels with commas
1370
- const labelsString = labelsArray.join(', ');
807
+ if (controls?.renderAs) {
808
+ dElement = document.createElement(controls.renderAs);
1371
809
 
1372
- // Assign the label string to pillText
1373
- pillText = `${foundItem.label}: ${labelsString}`;
810
+ if (controls?.attributes) {
811
+ for (let key in controls.attributes) {
812
+ if (controls.attributes.hasOwnProperty(key)) {
813
+ // Convert boolean to string if necessary
814
+ let value = controls.attributes[key];
815
+ let stringValue = (typeof value === 'boolean') ? value.toString() : value;
816
+ // Set the attribute on the element
817
+ dElement.setAttribute(key, stringValue);
1374
818
  }
1375
819
  }
820
+ }
1376
821
 
1377
- formPill.setAttribute('text', pillText.slice(0, 30) + (pillText.length > 30 ? "..." : ""))
1378
- let items = [];
1379
- if (this._state.criteriaList === null) {
1380
- for (let item of this._state.configData.filterCriteria.items) {
1381
- let lbValue = { 'label': item.label, 'value': item.value };
1382
- if (item.multiple) {
1383
- lbValue.multiple = item.multiple
1384
- }
1385
- items.push(lbValue);
1386
- }
1387
- this._state.criteriaList = items;
1388
- } else {
1389
- for (let item of this._state.criteriaList) {
1390
- items.push(item);
1391
- }
822
+ if (controls?.children?.length) {
823
+ let dChild
824
+ for (const child of controls.children) {
825
+ dChild = this.convertJsonToDom(child)
826
+ dElement.append(dChild)
1392
827
  }
1393
- let updatedList = this._state.criteriaList.filter(item => {
1394
- if (item.multiple) {
1395
- return true;
1396
- }
1397
- return item.value !== pill.value1;
1398
- });
1399
-
1400
- this._state.criteriaList = updatedList;
828
+ }
1401
829
 
830
+ if (controls?.relayEvents?.length) {
831
+ this.relayEvents(controls.relayEvents, dElement);
1402
832
  }
1403
833
  }
834
+
835
+ return dElement;
836
+ }
837
+
838
+ assignValueToFieldInPopover(oFields, dPopover) {
839
+ this.setExistingFieldValues(oFields, { 'dBody': dPopover.querySelector('.body-content') })
1404
840
  }
1405
841
 
1406
842
  validateRegion(dRegion) {
@@ -1424,6 +860,31 @@ class CUI_FORMPILL extends HTMLElement {
1424
860
  }
1425
861
  }
1426
862
 
863
+ relayEvents(asEvents, dElement) {
864
+ for (let event of asEvents) {
865
+
866
+ dElement.addEventListener(event, (e) => {
867
+
868
+ if (e.target != this) {
869
+
870
+ e.stopImmediatePropagation();
871
+
872
+ let eventDetail = e.detail;
873
+ eventDetail.originalTarget = e.target;
874
+ eventDetail.target = this;
875
+ const E_CONTROL_EVENT = new CustomEvent(event, {
876
+ bubbles: true,
877
+ composed: true,
878
+ detail: eventDetail
879
+ });
880
+
881
+ this.dispatchEvent(E_CONTROL_EVENT);
882
+ }
883
+
884
+ }, false);
885
+ }
886
+ }
887
+
1427
888
  _removeScreenValidationMessage() {
1428
889
  let messageText = "Please correct the highlighted errors shown below before continuing.";
1429
890
  if (this.messages) {
@@ -1431,10 +892,6 @@ class CUI_FORMPILL extends HTMLElement {
1431
892
  }
1432
893
  }
1433
894
 
1434
- /**
1435
- *
1436
- * @param {*} event
1437
- */
1438
895
  windowResize(event) {
1439
896
 
1440
897
  if (this._state.bMenuDisplayed == true) {
@@ -1443,10 +900,6 @@ class CUI_FORMPILL extends HTMLElement {
1443
900
 
1444
901
  }
1445
902
 
1446
- /**
1447
- *
1448
- * @returns
1449
- */
1450
903
  hidePopover() {
1451
904
  if (this._state.bMenuDisplayed == false) {
1452
905
  return;