gd-bs 6.7.5 → 6.7.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/indexv2.html CHANGED
@@ -177,7 +177,7 @@
177
177
 
178
178
  <h5>Dropdown</h5>
179
179
 
180
- <bs-dropdown auto-select="true" is-split="false" label="My Dropdown:" on-change="MyLib.ddlChange">
180
+ <bs-dropdown auto-select="true" is-split="false" label="My Dropdown:" search="true" on-change="MyLib.ddlChange">
181
181
  <item is-header="true">Header 1</item>
182
182
  <item is-divider="true"></item>
183
183
  <item value="1">Item 1</item>
@@ -545,7 +545,7 @@
545
545
  cardRender: (el) => { console.log("Card Render: ", el); },
546
546
  cardBodyRender: (el) => { console.log("Card Body Render: ", el); },
547
547
  collapseInit: obj => { window["collapseDemo"] = obj; },
548
- ddlChange: (item) => { alert("Selected Item: " + (item ? item.text : "No Selection")); },
548
+ ddlChange: (item) => { debugger; alert("Selected Item: " + (item ? item.text : "No Selection")); },
549
549
  fileClicked: (btn) => { alert(btn.text + " clicked."); },
550
550
  formCustomControl: (ctrl) => { ctrl.el.innerHTML = "<h3>Custom Control</h3>"; },
551
551
  inputGrouponChange: (val) => { console.log("Value changed to: " + val); },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gd-bs",
3
- "version": "6.7.5",
3
+ "version": "6.7.7",
4
4
  "description": "Bootstrap JavaScript, TypeScript and Web Components library.",
5
5
  "main": "build/index.js",
6
6
  "typings": "src/index.d.ts",
@@ -87,6 +87,9 @@ export class DropdownFormItem {
87
87
  // The component HTML element
88
88
  get el(): HTMLElement { return this._el; }
89
89
 
90
+ // Hides the item
91
+ hide() { this._el.classList.add("d-none"); }
92
+
90
93
  // Returns true if the item is selected
91
94
  get isSelected(): boolean { return this._isSelected; }
92
95
  set isSelected(value: boolean) { this._isSelected = value; }
@@ -94,6 +97,9 @@ export class DropdownFormItem {
94
97
  // The component properties
95
98
  get props(): IDropdownItem { return this._props; }
96
99
 
100
+ // Shows the item
101
+ show() { this._el.classList.remove("d-none"); }
102
+
97
103
  // Toggles the item selection
98
104
  toggle() {
99
105
  // Skip the dividers, headers
@@ -38,6 +38,7 @@ class _Dropdown extends Base<IDropdownProps> implements IDropdown {
38
38
  private _autoSelect: boolean = null;
39
39
  private _cb: ICheckboxGroup = null;
40
40
  private _elMenu: HTMLElement;
41
+ private _elSearch: HTMLInputElement;
41
42
  private _floatingUI: IFloatingUI = null;
42
43
  private _initFl: boolean = false;
43
44
  private _items: Array<DropdownFormItem | DropdownItem> = null;
@@ -52,6 +53,9 @@ class _Dropdown extends Base<IDropdownProps> implements IDropdown {
52
53
  // Configure the events
53
54
  this.configureEvents();
54
55
 
56
+ // Configure search
57
+ this.configureSearch();
58
+
55
59
  // Configure the parent
56
60
  this.configureParent();
57
61
 
@@ -258,6 +262,16 @@ class _Dropdown extends Base<IDropdownProps> implements IDropdown {
258
262
  elTarget: toggle,
259
263
  placement: typeof (this.props.placement) === "number" ? this.props.placement : FloatingUIPlacements.BottomStart,
260
264
  theme: popoverType,
265
+ onShow: () => {
266
+ // See if the search element exists
267
+ if (this._elSearch) {
268
+ // Clear the search
269
+ this._elSearch.value = "";
270
+
271
+ // Show all the items
272
+ for (let i = 0; i < this._items.length; i++) { this._items[i].show(); }
273
+ }
274
+ },
261
275
  options: {
262
276
  arrow: false,
263
277
  flip: true,
@@ -396,6 +410,73 @@ class _Dropdown extends Base<IDropdownProps> implements IDropdown {
396
410
  }
397
411
  }
398
412
 
413
+ // Configures the search option for the dropdown
414
+ private configureSearch() {
415
+ // See if search is enabled and the menu exists
416
+ if (this.props.search != true || this._elMenu == null) { return; }
417
+
418
+ // Create the search textbox
419
+ this._elSearch = document.createElement("input");
420
+ this._elSearch.classList.add("form-control");
421
+ this._elSearch.type = "search";
422
+ this._elSearch.placeholder = "Search for item...";
423
+
424
+ // Insert the item as the first element
425
+ this._elMenu.firstChild ? this._elMenu.insertBefore(this._elSearch, this._elMenu.firstChild) : this._elMenu.appendChild(this._elSearch);
426
+
427
+ // Create the empty text
428
+ let elEmptyText = document.createElement("h6")
429
+ elEmptyText.classList.add("dropdown-header");
430
+ elEmptyText.classList.add("d-none");
431
+ elEmptyText.innerHTML = "No items were found...";
432
+ this._elMenu.appendChild(elEmptyText);
433
+
434
+ // Add the element to the ignore list
435
+ this._floatingUI.addIgnoreElement(this._elSearch);
436
+
437
+ // Add the event
438
+ this._elSearch.addEventListener("input", () => {
439
+ // Get the value
440
+ let searchText = (this._elSearch.value || "").toLocaleLowerCase();
441
+
442
+ // Set the flags
443
+ let itemsFound = false;
444
+ let showAll = searchText == "";
445
+
446
+ // Hide the empty text
447
+ elEmptyText.classList.add("d-none");
448
+
449
+ // Parse the items
450
+ for (let i = 0; i < this._items.length; i++) {
451
+ let item = this._items[i];
452
+
453
+ // See if we are showing all the items
454
+ if (showAll) {
455
+ // Show the item
456
+ item.show();
457
+ } else {
458
+ // See if the value contains the text
459
+ if ((item.props.text || "").toLowerCase().indexOf(searchText) >= 0) {
460
+ // Show the item
461
+ item.show();
462
+
463
+ // Set the flag
464
+ itemsFound = true;
465
+ } else {
466
+ // Hide the item
467
+ item.hide();
468
+ }
469
+ }
470
+ }
471
+
472
+ // See if no items were found
473
+ if (!showAll && !itemsFound) {
474
+ // Show the empty message
475
+ elEmptyText.classList.remove("d-none");
476
+ }
477
+ });
478
+ }
479
+
399
480
  // Generates the checkbox items
400
481
  private generateCheckboxItems(): ICheckboxGroupItem[] {
401
482
  let cbItems: ICheckboxGroupItem[] = [];
@@ -644,6 +725,9 @@ class _Dropdown extends Base<IDropdownProps> implements IDropdown {
644
725
  }
645
726
  }
646
727
  }
728
+
729
+ // Configure search
730
+ this.configureSearch();
647
731
  }
648
732
 
649
733
  // Sets the label of the dropdown
@@ -153,12 +153,18 @@ export class DropdownItem {
153
153
  // The component HTML element
154
154
  get el(): HTMLElement { return this._el; }
155
155
 
156
+ // Hides the item
157
+ hide() { this._el.classList.add("d-none"); }
158
+
156
159
  // Returns true if the item is selected
157
160
  get isSelected(): boolean { return this._isSelected; }
158
161
 
159
162
  // The component properties
160
163
  get props(): IDropdownItem { return this._props; }
161
164
 
165
+ // Shows the item
166
+ show() { this._el.classList.remove("d-none"); }
167
+
162
168
  // Toggles the item selection
163
169
  toggle() {
164
170
  // Skip the dividers, headers and nav items
@@ -155,6 +155,7 @@ export interface IDropdownProps extends IBaseProps<IDropdown> {
155
155
  onMenuRendering?: (props: IFloatingUIProps) => IFloatingUIProps;
156
156
  placement?: number;
157
157
  required?: boolean;
158
+ search?: boolean;
158
159
  title?: string;
159
160
  type?: number;
160
161
  updateLabel?: boolean;
@@ -1,4 +1,6 @@
1
- import { arrow, autoPlacement, computePosition, flip, hide, inline, offset, shift, size, ComputePositionConfig } from "@floating-ui/dom";
1
+ import {
2
+ arrow, autoPlacement, computePosition, flip, hide, inline, offset, shift, size, ComputePositionConfig
3
+ } from "@floating-ui/dom";
2
4
  import { setClassNames } from "../common";
3
5
  import { IFloatingUIProps, IFloatingUI } from "./types";
4
6
  export * as FloatingUILib from "@floating-ui/dom";
@@ -47,18 +49,15 @@ export enum FloatingUITypes {
47
49
  */
48
50
  class _FloatingUI {
49
51
  private _elArrow: HTMLElement = null;
50
- private _elTarget: HTMLElement = null;
51
52
  private _elContent: HTMLElement = null;
53
+ private _elIgnore: HTMLElement[] = null;
54
+ private _elTarget: HTMLElement = null;
52
55
  private _options: ComputePositionConfig = null;
53
56
  private _props: IFloatingUIProps = null;
54
57
 
55
- // Static events
56
- private static Events = [];
57
- private static EventsCreated = false;
58
- private static ScrollEvents = [];
59
-
60
58
  // Constructor
61
59
  constructor(props: IFloatingUIProps) {
60
+ this._elIgnore = [];
62
61
  this._elTarget = props.elTarget;
63
62
  this._props = props;
64
63
 
@@ -80,6 +79,7 @@ class _FloatingUI {
80
79
  this._props.show ? this.show() : this.hide();
81
80
  }
82
81
 
82
+ // Add the events to trigger, refresh and hide the element
83
83
  private addEvents(trigger: string = "") {
84
84
  // Events
85
85
  if (trigger.indexOf("mouse") >= 0) {
@@ -97,48 +97,29 @@ class _FloatingUI {
97
97
  });
98
98
  }
99
99
 
100
- // Add the events
101
- _FloatingUI.Events.push((ev: Event) => {
102
- // See if it's outside the target element
103
- if (!this._elTarget.contains(ev.target as any)) {
104
- // Hide the element
105
- this.hide();
106
- }
107
- });
108
- _FloatingUI.ScrollEvents.push((ev: Event) => {
109
- // Refresh the content
110
- this.refresh();
111
- });
100
+ // Create the event
101
+ document.addEventListener("click", (ev) => {
102
+ // Do nothing if we toggled this component
103
+ if (this._elTarget.contains(ev.target as HTMLElement)) { return; }
112
104
 
113
- // Ensure the click event exists
114
- if (!_FloatingUI.EventsCreated) {
115
- // Create the event
116
- document.addEventListener("click", (ev) => {
117
- // Wait for the other events to run
118
- setTimeout(() => {
119
- // Parse the events
120
- _FloatingUI.Events.forEach(fnEvent => {
121
- // Call the event
122
- fnEvent(ev);
123
- });
124
- }, 10);
125
- });
105
+ // Parse the elements to ignore
106
+ for (let i = 0; i < this._elIgnore.length; i++) {
107
+ // Do nothing if it triggered the click
108
+ if (this._elIgnore[i].contains(ev.target as HTMLElement)) { return; }
109
+ }
126
110
 
127
- // Create the scroll event
128
- window.addEventListener("scroll", (ev) => {
129
- // Wait for the other events to run
130
- setTimeout(() => {
131
- // Parse the events
132
- _FloatingUI.ScrollEvents.forEach(fnEvent => {
133
- // Call the event
134
- fnEvent(ev);
135
- });
136
- }, 10);
137
- });
111
+ // Hide the element
112
+ this.hide();
113
+ });
138
114
 
139
- // Set the flag
140
- _FloatingUI.EventsCreated = true;
141
- }
115
+ // Create the scroll event
116
+ window.addEventListener("scroll", (ev) => {
117
+ // Wait for the other events to run
118
+ setTimeout(() => {
119
+ // Refresh the content
120
+ this.refresh();
121
+ }, 10);
122
+ });
142
123
  }
143
124
 
144
125
  // Creates the floating ui
@@ -367,13 +348,33 @@ class _FloatingUI {
367
348
  * Public Methods
368
349
  */
369
350
 
370
- setContent(el) { this._elContent = el; }
351
+ addIgnoreElement(el: HTMLElement) { this._elIgnore.push(el); }
352
+
353
+ removeIgnoreElement(el: HTMLElement) {
354
+ // Parse the elements
355
+ for (let i = 0; i < this._elIgnore.length; i++) {
356
+ // See if this is the element to remove
357
+ if (this._elIgnore[i].isEqualNode(el)) {
358
+ // Remove it
359
+ this._elIgnore.splice(i, 1);
360
+ return;
361
+ }
362
+ }
363
+ }
364
+
365
+ setContent(el) { this._elContent = el; this.refresh(); }
371
366
 
372
367
  // Hides the content
373
368
  hide() {
374
369
  // Remove it from the document
375
370
  this._elContent.classList.add("d-none");
376
- if (document.body.contains(this._elContent)) { document.body.removeChild(this._elContent); }
371
+ if (document.body.contains(this._elContent)) {
372
+ // Remove the element from the page
373
+ document.body.removeChild(this._elContent);
374
+
375
+ // Call the event
376
+ this._props.onHide ? this._props.onHide() : null;
377
+ }
377
378
  }
378
379
 
379
380
  // Determines if the content is visible
@@ -383,7 +384,16 @@ class _FloatingUI {
383
384
  show() {
384
385
  // Append it to the document
385
386
  this._elContent.classList.remove("d-none");
386
- if (!document.body.contains(this._elContent)) { document.body.appendChild(this._elContent); this.refresh(); }
387
+ if (!document.body.contains(this._elContent)) {
388
+ // Add the element to the page
389
+ document.body.appendChild(this._elContent);
390
+
391
+ // Refresh the position
392
+ this.refresh();
393
+
394
+ // Call the event
395
+ this._props.onShow ? this._props.onShow() : null;
396
+ }
387
397
  }
388
398
 
389
399
  // Toggles the floating ui
@@ -5,8 +5,10 @@ import { IBaseProps } from "../types";
5
5
  export const FloatingUIPlacements: IFloatingUIPlacements;
6
6
 
7
7
  export interface IFloatingUI {
8
+ addIgnoreElement: (el: Element) => void;
8
9
  hide: () => void;
9
10
  isVisible: boolean;
11
+ removeIgnoreElement: (el: Element) => void;
10
12
  setContent: (el: string | Element) => void;
11
13
  show: () => void;
12
14
  toggle: () => void;
@@ -29,6 +31,8 @@ export interface IFloatingUIOptions {
29
31
  export interface IFloatingUIProps extends IBaseProps<IFloatingUI> {
30
32
  elContent: HTMLElement;
31
33
  elTarget: HTMLElement;
34
+ onHide?: (el?: HTMLElement) => void;
35
+ onShow?: (el?: HTMLElement) => void;
32
36
  options?: IFloatingUIOptions;
33
37
  placement?: number;
34
38
  show?: boolean;