@peckadesign/pd-naja 1.5.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,34 @@
1
+ import { SpinnerPropsFn, SpinnerType } from '../types';
2
+ type SuggestOptions = {
3
+ minLength: number;
4
+ timeout: number;
5
+ };
6
+ export declare class Suggest {
7
+ readonly spinner?: SpinnerType;
8
+ readonly getSpinnerProps?: SpinnerPropsFn;
9
+ static readonly className = "js-suggest";
10
+ readonly inputClassName: string;
11
+ readonly buttonClassName: string;
12
+ readonly suggestClassName: string;
13
+ readonly linkClassName: string;
14
+ private readonly form;
15
+ private readonly input;
16
+ private readonly button;
17
+ private readonly suggest;
18
+ private suggestSpinner;
19
+ private isOpen;
20
+ private timer;
21
+ private lastSearched;
22
+ private readonly options;
23
+ constructor(form: HTMLFormElement, options?: Partial<SuggestOptions>, spinner?: SpinnerType | undefined, getSpinnerProps?: SpinnerPropsFn);
24
+ private isEmpty;
25
+ private showSuggest;
26
+ private hideSuggest;
27
+ private emptySuggest;
28
+ startSuggest(): void;
29
+ finishSuggest(): void;
30
+ private handleInputKeydown;
31
+ private handleInputKeyup;
32
+ private handleSuggestMousedown;
33
+ }
34
+ export {};
@@ -1,22 +1,18 @@
1
1
  import { Extension, Naja } from 'naja/dist/Naja';
2
+ import { SpinnerPropsFn, SpinnerType, WithSpinner } from '../types';
2
3
  declare module 'naja/dist/Naja' {
3
4
  interface Options {
4
5
  btnSpinnerInitiator?: Element;
5
6
  btnSpinner?: Element;
6
7
  }
7
8
  }
8
- type spinnerType = ((props?: any) => Element) | Element;
9
- type spinnerPropsFn = ((initiator: Element) => any) | undefined;
10
- export declare class BtnSpinnerExtension implements Extension {
9
+ export declare class BtnSpinnerExtension implements Extension, WithSpinner {
11
10
  readonly timeout: number;
12
- readonly spinner: spinnerType;
13
- readonly getSpinnerProps?: spinnerPropsFn;
14
- constructor(spinner: spinnerType, getSpinnerProps?: spinnerPropsFn, timeout?: number);
11
+ readonly spinner: SpinnerType;
12
+ readonly getSpinnerProps: SpinnerPropsFn;
13
+ constructor(spinner: SpinnerType, getSpinnerProps?: SpinnerPropsFn, timeout?: number);
15
14
  initialize(naja: Naja): void;
16
15
  private checkExtensionEnabled;
17
16
  private handleStartEvent;
18
17
  private handleCompleteEvent;
19
- private showSpinner;
20
- private hideSpinner;
21
18
  }
22
- export {};
@@ -0,0 +1,16 @@
1
+ import { Extension, Naja } from 'naja/dist/Naja';
2
+ type NajaScrollToEvent = 'before' | 'success';
3
+ declare module 'naja/dist/Naja' {
4
+ interface Options {
5
+ scrollToEvent?: NajaScrollToEvent;
6
+ scrollToSelector?: string;
7
+ }
8
+ }
9
+ export declare class ScrollToExtension implements Extension {
10
+ defaultScrollToEvent: NajaScrollToEvent;
11
+ constructor(defaultScrollToEvent?: NajaScrollToEvent);
12
+ initialize(naja: Naja): void;
13
+ private checkExtensionEnabled;
14
+ private checkScroll;
15
+ }
16
+ export {};
@@ -1,4 +1,5 @@
1
1
  import { Extension, Naja } from 'naja/dist/Naja';
2
+ import { SpinnerPropsFn, SpinnerType, WithSpinner } from '../types';
2
3
  /**
3
4
  * @author Radek Šerý
4
5
  *
@@ -17,14 +18,12 @@ declare module 'naja/dist/Naja' {
17
18
  spinnerInitiator?: Element;
18
19
  }
19
20
  }
20
- type spinnerType = ((props?: any) => Element) | Element;
21
- type spinnerPropsFn = ((initiator: Element) => any) | undefined;
22
- export declare class SpinnerExtension implements Extension {
23
- readonly spinner: spinnerType;
24
- readonly getSpinnerProps?: spinnerPropsFn;
21
+ export declare class SpinnerExtension implements Extension, WithSpinner {
22
+ readonly spinner: SpinnerType;
23
+ readonly getSpinnerProps: SpinnerPropsFn;
25
24
  readonly ajaxSpinnerWrapSelector: string;
26
25
  readonly ajaxSpinnerPlaceholderSelector: string;
27
- constructor(spinner: spinnerType, getSpinnerProps?: spinnerPropsFn, ajaxSpinnerWrapSelector?: string, ajaxSpinnerPlaceholderSelector?: string);
26
+ constructor(spinner: SpinnerType, getSpinnerProps?: SpinnerPropsFn, ajaxSpinnerWrapSelector?: string, ajaxSpinnerPlaceholderSelector?: string);
28
27
  initialize(naja: Naja): void;
29
28
  private getSpinnerInitiator;
30
29
  private showSpinners;
@@ -33,4 +32,3 @@ export declare class SpinnerExtension implements Extension {
33
32
  private getPlaceholdersByQuerySelector;
34
33
  private getPlaceholdersByDOM;
35
34
  }
36
- export {};
@@ -0,0 +1,18 @@
1
+ import { Extension, Naja } from 'naja/dist/Naja';
2
+ import { Suggest } from '../classes/Suggest';
3
+ import { SpinnerPropsFn, SpinnerType } from '../types';
4
+ declare module 'naja/dist/Naja' {
5
+ interface Options {
6
+ suggest?: Suggest;
7
+ }
8
+ }
9
+ export declare class SuggestExtension implements Extension {
10
+ private requestQueue;
11
+ readonly spinner: SpinnerType | undefined;
12
+ readonly getSpinnerProps?: SpinnerPropsFn;
13
+ constructor(spinner?: SpinnerType | undefined, getSpinnerProps?: SpinnerPropsFn);
14
+ initialize(naja: Naja): void;
15
+ private checkExtensionEnabled;
16
+ private start;
17
+ private complete;
18
+ }
@@ -0,0 +1,19 @@
1
+ import { Extension, Naja } from 'naja/dist/Naja';
2
+ type ToggleClassRecord = Record<string, string>;
3
+ type ToggleClassOptions = {
4
+ element: Element;
5
+ toggleClass: ToggleClassRecord;
6
+ };
7
+ declare module 'naja/dist/Naja' {
8
+ interface Options {
9
+ toggleClassOptions?: ToggleClassOptions;
10
+ }
11
+ }
12
+ export declare class ToggleClassExtension implements Extension {
13
+ initialize(naja: Naja): void;
14
+ private checkExtensionEnabled;
15
+ private start;
16
+ private complete;
17
+ private applyToggleClass;
18
+ }
19
+ export {};
@@ -1,4 +1,5 @@
1
- import ControlManager from './utils/ControlManager';
1
+ export { ControlManager } from './classes/ControlManager';
2
+ export { Suggest } from './classes/Suggest';
2
3
  export { AjaxModalExtension } from './extensions/AjaxModalExtension';
3
4
  export { AjaxModalPreventRedrawExtension } from './extensions/AjaxModalPreventRedrawExtension';
4
5
  export { AjaxOnceExtension } from './extensions/AjaxOnceExtension';
@@ -7,8 +8,10 @@ export { ConfirmExtension } from './extensions/ConfirmExtension';
7
8
  export { FollowUpRequestExtension } from './extensions/FollowUpRequestExtension';
8
9
  export { ForceRedirectExtension } from './extensions/ForceRedirectExtension';
9
10
  export { ForceReplaceExtension } from './extensions/ForceReplaceExtension';
11
+ export { ScrollToExtension } from './extensions/ScrollToExtension';
10
12
  export { SingleSubmitExtension } from './extensions/SingleSubmitExtension';
11
13
  export { SnippetFormPartExtension } from './extensions/SnippetFormPartExtension';
12
14
  export { SpinnerExtension } from './extensions/SpinnerExtension';
13
- export { isDatasetTruthy, isDatasetFalsy } from './utils';
14
- export declare const controlManager: ControlManager;
15
+ export { SuggestExtension } from './extensions/SuggestExtension';
16
+ export { ToggleClassExtension } from './extensions/ToggleClassExtension';
17
+ export { isDatasetFalsy, isDatasetTruthy, showSpinner, hideSpinner } from './utils';
package/dist/index.esm.js CHANGED
@@ -5,21 +5,20 @@
5
5
  * @author PeckaDesign, s.r.o <support@peckadesign.cz>
6
6
  * @license MIT
7
7
  *
8
- * @version 1.5.2
8
+ * @version 2.0.0
9
9
  */
10
10
 
11
- import naja from 'naja';
12
-
13
11
  let instance = null;
14
12
  class ControlManager {
15
- constructor() {
13
+ constructor(naja) {
16
14
  this.onLoadControl = [];
17
15
  this.onLiveControl = [];
18
16
  if (instance === null) {
19
17
  // eslint-disable-next-line @typescript-eslint/no-this-alias
20
18
  instance = this;
21
- naja.snippetHandler.addEventListener('beforeUpdate', this.onBeforeSnippetUpdate.bind(this));
22
- naja.snippetHandler.addEventListener('afterUpdate', this.onSnippetUpdate.bind(this));
19
+ this.naja = naja;
20
+ this.naja.snippetHandler.addEventListener('beforeUpdate', this.onBeforeSnippetUpdate.bind(this));
21
+ this.naja.snippetHandler.addEventListener('afterUpdate', this.onSnippetUpdate.bind(this));
23
22
  }
24
23
  return instance;
25
24
  }
@@ -28,8 +27,8 @@ class ControlManager {
28
27
  this.initialize(this.onLiveControl);
29
28
  }
30
29
  onBeforeSnippetUpdate(event) {
31
- if (event.detail.operation === naja.snippetHandler.op.append ||
32
- event.detail.operation === naja.snippetHandler.op.prepend) {
30
+ if (event.detail.operation === this.naja.snippetHandler.op.append ||
31
+ event.detail.operation === this.naja.snippetHandler.op.prepend) {
33
32
  return;
34
33
  }
35
34
  this.destroy(this.onLiveControl, event.detail.snippet);
@@ -57,6 +56,180 @@ class ControlManager {
57
56
  }
58
57
  }
59
58
 
59
+ function showSpinner(target, initiator = target) {
60
+ let spinner;
61
+ if (typeof this.spinner === 'function') {
62
+ spinner = this.getSpinnerProps ? this.spinner(this.getSpinnerProps(initiator)) : this.spinner();
63
+ }
64
+ else {
65
+ spinner = this.spinner;
66
+ }
67
+ target.appendChild(spinner);
68
+ spinner.animate([{ opacity: 0 }, { opacity: 1 }], { duration: 100 });
69
+ return spinner;
70
+ }
71
+ function hideSpinner(spinner) {
72
+ const animation = spinner.animate({ opacity: 0 }, { duration: 100 });
73
+ animation.finished.then(() => spinner?.remove());
74
+ }
75
+ const isDatasetTruthy = (element, datasetName) => {
76
+ const datasetValue = element.dataset[datasetName];
77
+ return datasetValue !== undefined && datasetValue !== 'false' && datasetValue !== 'off';
78
+ };
79
+ const isDatasetFalsy = (element, datasetName) => {
80
+ const datasetValue = element.dataset[datasetName];
81
+ return datasetValue === 'off' || datasetValue === 'false';
82
+ };
83
+
84
+ class Suggest {
85
+ constructor(form, options = {}, spinner = undefined, getSpinnerProps = undefined) {
86
+ this.inputClassName = `${Suggest.className}__input`;
87
+ this.buttonClassName = `${Suggest.className}__btn`;
88
+ this.suggestClassName = `${Suggest.className}__suggest`;
89
+ this.linkClassName = `${Suggest.className}__link`;
90
+ this.isOpen = false;
91
+ this.timer = undefined;
92
+ this.lastSearched = '';
93
+ this.options = {
94
+ minLength: 2,
95
+ timeout: 200
96
+ };
97
+ this.form = form;
98
+ this.spinner = spinner;
99
+ this.getSpinnerProps = getSpinnerProps;
100
+ const input = form.querySelector(`.${this.inputClassName}`);
101
+ const button = form.querySelector(`.${this.buttonClassName}`);
102
+ const suggest = form.querySelector(`.${this.suggestClassName}`);
103
+ if (!input || !button || !suggest) {
104
+ throw new Error('Suggest: Missing input, button or suggest element.');
105
+ }
106
+ this.input = input;
107
+ this.button = button;
108
+ this.suggest = suggest;
109
+ this.options = { ...this.options, ...options };
110
+ this.input.addEventListener('focus', this.showSuggest.bind(this));
111
+ this.input.addEventListener('blur', this.hideSuggest.bind(this));
112
+ this.input.addEventListener('keydown', this.handleInputKeydown.bind(this));
113
+ this.input.addEventListener('keyup', this.handleInputKeyup.bind(this));
114
+ this.suggest.addEventListener('mousedown', this.handleSuggestMousedown.bind(this));
115
+ this.form._suggest = this;
116
+ }
117
+ isEmpty() {
118
+ return this.suggest.childElementCount === 0;
119
+ }
120
+ showSuggest() {
121
+ if (this.isEmpty() || this.input.value.length < this.options.minLength) {
122
+ return;
123
+ }
124
+ const event = new CustomEvent('show.suggest', { bubbles: true, cancelable: true });
125
+ this.suggest.dispatchEvent(event);
126
+ if (event.defaultPrevented) {
127
+ return;
128
+ }
129
+ this.isOpen = true;
130
+ this.suggest.classList.add(`${this.suggestClassName}--shown`);
131
+ }
132
+ hideSuggest() {
133
+ const event = new CustomEvent('hide.suggest', { bubbles: true, cancelable: true });
134
+ this.suggest.dispatchEvent(event);
135
+ if (event.defaultPrevented) {
136
+ return;
137
+ }
138
+ this.isOpen = false;
139
+ this.suggest.classList.remove(`${this.suggestClassName}--shown`);
140
+ }
141
+ emptySuggest() {
142
+ this.suggest.classList.add(`${this.suggestClassName}--empty`);
143
+ this.suggest.replaceChildren();
144
+ }
145
+ startSuggest() {
146
+ this.suggest.dispatchEvent(new CustomEvent('loading.suggest', { bubbles: true }));
147
+ this.input.classList.add(`${this.inputClassName}--loading`);
148
+ if (this.spinner && !this.suggestSpinner) {
149
+ this.suggestSpinner = showSpinner.call(this, this.form);
150
+ }
151
+ }
152
+ finishSuggest() {
153
+ this.suggest.dispatchEvent(new CustomEvent('loaded.suggest', { bubbles: true }));
154
+ this.input.classList.remove(`${this.inputClassName}--loading`);
155
+ this.suggest.classList.toggle(`${this.suggestClassName}--empty`, this.isEmpty());
156
+ if (this.isEmpty() || document.activeElement !== this.input) {
157
+ this.hideSuggest();
158
+ }
159
+ else {
160
+ this.showSuggest();
161
+ }
162
+ if (this.suggestSpinner) {
163
+ hideSpinner(this.suggestSpinner);
164
+ this.suggestSpinner = undefined;
165
+ }
166
+ }
167
+ handleInputKeydown(event) {
168
+ let anchors;
169
+ let activeAnchor;
170
+ let activeAnchorIndex;
171
+ const activeClassName = `${this.linkClassName}--active`;
172
+ switch (event.key) {
173
+ case 'Escape':
174
+ event.preventDefault();
175
+ this.hideSuggest();
176
+ this.input.blur();
177
+ break;
178
+ case 'ArrowDown':
179
+ case 'ArrowUp':
180
+ event.preventDefault();
181
+ anchors = Array.from(this.suggest.querySelectorAll(`.${this.linkClassName}`));
182
+ activeAnchor = anchors.find((element) => element.classList.contains(activeClassName));
183
+ activeAnchorIndex = activeAnchor ? anchors.indexOf(activeAnchor) : undefined;
184
+ activeAnchor?.classList.remove(activeClassName);
185
+ if (event.key === 'ArrowDown') {
186
+ activeAnchorIndex = activeAnchorIndex !== undefined ? activeAnchorIndex + 1 : 0;
187
+ }
188
+ else {
189
+ activeAnchorIndex = activeAnchorIndex !== undefined ? activeAnchorIndex - 1 : anchors.length - 1;
190
+ }
191
+ anchors[activeAnchorIndex]?.classList.add(activeClassName);
192
+ break;
193
+ case 'Enter':
194
+ activeAnchor = this.suggest.querySelector(`.${activeClassName}`);
195
+ if (activeAnchor) {
196
+ event.preventDefault();
197
+ event.stopPropagation();
198
+ location.href = activeAnchor.href;
199
+ }
200
+ break;
201
+ }
202
+ }
203
+ handleInputKeyup() {
204
+ clearTimeout(this.timer);
205
+ const query = this.input.value;
206
+ if (query.length < this.options.minLength) {
207
+ this.hideSuggest();
208
+ return;
209
+ }
210
+ if (!this.isOpen) {
211
+ // If the suggestion wasn't open and this query is different from the last query, we need to clear the
212
+ // results because they are not relevant. This only needs to be done if the suggestion has been closed.
213
+ if (query !== this.lastSearched) {
214
+ this.emptySuggest();
215
+ }
216
+ this.showSuggest();
217
+ }
218
+ // If the query is the same, there's nothing more to do.
219
+ if (query === this.lastSearched) {
220
+ return;
221
+ }
222
+ this.timer = setTimeout(() => {
223
+ this.lastSearched = query;
224
+ this.button.click();
225
+ }, this.options.timeout);
226
+ }
227
+ handleSuggestMousedown(event) {
228
+ event.preventDefault();
229
+ }
230
+ }
231
+ Suggest.className = 'js-suggest';
232
+
60
233
  class AjaxModalExtension {
61
234
  constructor(modal) {
62
235
  this.uniqueExtKey = 'modal';
@@ -373,15 +546,6 @@ class AjaxModalPreventRedrawExtension {
373
546
  }
374
547
  }
375
548
 
376
- const isDatasetTruthy = (element, datasetName) => {
377
- const datasetValue = element.dataset[datasetName];
378
- return datasetValue !== undefined && datasetValue !== 'false' && datasetValue !== 'off';
379
- };
380
- const isDatasetFalsy = (element, datasetName) => {
381
- const datasetValue = element.dataset[datasetName];
382
- return datasetValue === 'off' || datasetValue === 'false';
383
- };
384
-
385
549
  class AjaxOnceExtension {
386
550
  initialize(naja) {
387
551
  naja.uiHandler.addEventListener('interaction', this.checkAjaxOnce.bind(this));
@@ -422,9 +586,9 @@ class BtnSpinnerExtension {
422
586
  isDatasetTruthy(button, 'noBtnSpinner')) {
423
587
  return true;
424
588
  }
425
- const spinner = this.showSpinner(button);
589
+ const spinner = showSpinner.call(this, button);
426
590
  form.dataset.btnSpinnerTimeout = String(setTimeout(() => {
427
- this.hideSpinner(spinner);
591
+ hideSpinner(spinner);
428
592
  delete form.dataset.btnSpinnerTimeout;
429
593
  }, this.timeout));
430
594
  });
@@ -446,30 +610,14 @@ class BtnSpinnerExtension {
446
610
  if (!options.btnSpinnerInitiator) {
447
611
  return;
448
612
  }
449
- options.btnSpinner = this.showSpinner(options.btnSpinnerInitiator);
613
+ options.btnSpinner = showSpinner.call(this, options.btnSpinnerInitiator);
450
614
  }
451
615
  handleCompleteEvent(event) {
452
616
  const { options } = event.detail;
453
617
  if (options.forceRedirect || !options.btnSpinner) {
454
618
  return;
455
619
  }
456
- this.hideSpinner(options.btnSpinner);
457
- }
458
- showSpinner(button) {
459
- let spinner;
460
- if (typeof this.spinner === 'function') {
461
- spinner = this.getSpinnerProps ? this.spinner(this.getSpinnerProps(button)) : this.spinner();
462
- }
463
- else {
464
- spinner = this.spinner;
465
- }
466
- button.appendChild(spinner);
467
- spinner.animate([{ opacity: 0 }, { opacity: 1 }], { duration: 100 });
468
- return spinner;
469
- }
470
- hideSpinner(spinner) {
471
- const animation = spinner.animate({ opacity: 0 }, { duration: 100 });
472
- animation.finished.then(() => spinner?.remove());
620
+ hideSpinner(options.btnSpinner);
473
621
  }
474
622
  }
475
623
 
@@ -535,6 +683,36 @@ class ForceReplaceExtension {
535
683
  }
536
684
  }
537
685
 
686
+ class ScrollToExtension {
687
+ constructor(defaultScrollToEvent) {
688
+ this.defaultScrollToEvent = 'before';
689
+ if (defaultScrollToEvent) {
690
+ this.defaultScrollToEvent = defaultScrollToEvent;
691
+ }
692
+ }
693
+ initialize(naja) {
694
+ naja.uiHandler.addEventListener('interaction', this.checkExtensionEnabled.bind(this));
695
+ naja.addEventListener('before', this.checkScroll.bind(this));
696
+ naja.addEventListener('success', this.checkScroll.bind(this));
697
+ }
698
+ checkExtensionEnabled(event) {
699
+ const { element, options } = event.detail;
700
+ const selector = element.getAttribute('data-naja-scroll-to');
701
+ if (selector) {
702
+ const event = element.getAttribute('data-naja-scroll-to-event');
703
+ options.scrollToSelector = selector;
704
+ options.scrollToEvent = event ?? this.defaultScrollToEvent;
705
+ }
706
+ }
707
+ checkScroll(event) {
708
+ const { options } = event.detail;
709
+ if (options.scrollToSelector && event.type === options.scrollToEvent) {
710
+ const scrollToElement = document.querySelector(options.scrollToSelector);
711
+ scrollToElement?.scrollIntoView();
712
+ }
713
+ }
714
+ }
715
+
538
716
  class SingleSubmitExtension {
539
717
  constructor(buttonDisabledClass, timeout = 60000) {
540
718
  this.timeout = 60000;
@@ -677,16 +855,7 @@ class SpinnerExtension {
677
855
  else {
678
856
  options.spinnerQueue = options.spinnerQueue || [];
679
857
  placeholders.forEach((placeholder) => {
680
- let spinner;
681
- if (typeof this.spinner === 'function') {
682
- spinner = this.getSpinnerProps ? this.spinner(this.getSpinnerProps(spinnerInitiator)) : this.spinner();
683
- }
684
- else {
685
- spinner = this.spinner;
686
- }
687
- placeholder.appendChild(spinner);
688
- options.spinnerQueue.push(spinner);
689
- spinner.animate([{ opacity: 0 }, { opacity: 1 }], { duration: 100 });
858
+ options.spinnerQueue.push(showSpinner.call(this, placeholder, spinnerInitiator));
690
859
  });
691
860
  }
692
861
  }
@@ -695,10 +864,7 @@ class SpinnerExtension {
695
864
  if (options.forceRedirect) {
696
865
  return;
697
866
  }
698
- options.spinnerQueue?.forEach((spinner) => {
699
- const animation = spinner.animate({ opacity: 0 }, { duration: 100 });
700
- animation.finished.then(() => spinner.remove());
701
- });
867
+ options.spinnerQueue?.forEach((spinner) => hideSpinner(spinner));
702
868
  }
703
869
  getPlaceholders(element) {
704
870
  if (!element) {
@@ -725,7 +891,84 @@ class SpinnerExtension {
725
891
  }
726
892
  }
727
893
 
728
- const controlManager = new ControlManager();
894
+ class SuggestExtension {
895
+ constructor(spinner = undefined, getSpinnerProps = undefined) {
896
+ this.requestQueue = new Set();
897
+ this.spinner = spinner;
898
+ this.getSpinnerProps = getSpinnerProps;
899
+ const forms = document.querySelectorAll(`.${Suggest.className}`);
900
+ forms.forEach((form) => {
901
+ new Suggest(form, {}, spinner, getSpinnerProps);
902
+ });
903
+ }
904
+ initialize(naja) {
905
+ naja.uiHandler.addEventListener('interaction', this.checkExtensionEnabled.bind(this));
906
+ naja.addEventListener('start', this.start.bind(this));
907
+ naja.addEventListener('complete', this.complete.bind(this));
908
+ }
909
+ checkExtensionEnabled(event) {
910
+ const { element, options } = event.detail;
911
+ const inputElement = element;
912
+ if (inputElement.form && inputElement.form._suggest) {
913
+ options.suggest = inputElement.form._suggest;
914
+ }
915
+ }
916
+ start(event) {
917
+ const { options, request } = event.detail;
918
+ if (options.suggest) {
919
+ this.requestQueue.add(request);
920
+ options.suggest.startSuggest();
921
+ }
922
+ }
923
+ complete(event) {
924
+ const { options, request } = event.detail;
925
+ if (!options.suggest) {
926
+ return;
927
+ }
928
+ this.requestQueue.delete(request);
929
+ if (this.requestQueue.size === 0) {
930
+ options.suggest.finishSuggest();
931
+ }
932
+ }
933
+ }
934
+
935
+ class ToggleClassExtension {
936
+ initialize(naja) {
937
+ naja.uiHandler.addEventListener('interaction', this.checkExtensionEnabled.bind(this));
938
+ naja.addEventListener('start', this.start.bind(this));
939
+ naja.addEventListener('complete', this.complete.bind(this));
940
+ }
941
+ checkExtensionEnabled(event) {
942
+ const { element, options } = event.detail;
943
+ const toggleClass = JSON.parse(element.getAttribute('data-naja-toggle-class') || String(null));
944
+ if (toggleClass) {
945
+ options.toggleClassOptions = {
946
+ element,
947
+ toggleClass
948
+ };
949
+ }
950
+ }
951
+ start(event) {
952
+ const { options } = event.detail;
953
+ if (options.toggleClassOptions) {
954
+ this.applyToggleClass(options.toggleClassOptions);
955
+ }
956
+ }
957
+ complete(event) {
958
+ const { error, options } = event.detail;
959
+ if (error && options.toggleClassOptions) {
960
+ this.applyToggleClass(options.toggleClassOptions);
961
+ }
962
+ }
963
+ applyToggleClass(toggleClassOptions) {
964
+ for (const [selector, classNames] of Object.entries(toggleClassOptions.toggleClass)) {
965
+ const targets = toggleClassOptions.element.querySelectorAll(selector);
966
+ targets.forEach((target) => {
967
+ classNames.split(' ').forEach((className) => target.classList.toggle(className));
968
+ });
969
+ }
970
+ }
971
+ }
729
972
 
730
- export { AjaxModalExtension, AjaxModalPreventRedrawExtension, AjaxOnceExtension, BtnSpinnerExtension, ConfirmExtension, FollowUpRequestExtension, ForceRedirectExtension, ForceReplaceExtension, SingleSubmitExtension, SnippetFormPartExtension, SpinnerExtension, controlManager, isDatasetFalsy, isDatasetTruthy };
973
+ export { AjaxModalExtension, AjaxModalPreventRedrawExtension, AjaxOnceExtension, BtnSpinnerExtension, ConfirmExtension, ControlManager, FollowUpRequestExtension, ForceRedirectExtension, ForceReplaceExtension, ScrollToExtension, SingleSubmitExtension, SnippetFormPartExtension, SpinnerExtension, Suggest, SuggestExtension, ToggleClassExtension, hideSpinner, isDatasetFalsy, isDatasetTruthy, showSpinner };
731
974
  //# sourceMappingURL=index.esm.js.map