selective-ui 1.2.4 → 1.2.5
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/dist/selective-ui.esm.js +4174 -1237
- package/dist/selective-ui.esm.js.map +1 -1
- package/dist/selective-ui.esm.min.js +2 -2
- package/dist/selective-ui.esm.min.js.br +0 -0
- package/dist/selective-ui.min.js +2 -2
- package/dist/selective-ui.min.js.br +0 -0
- package/dist/selective-ui.umd.js +4175 -1238
- package/dist/selective-ui.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/ts/adapter/mixed-adapter.ts +247 -91
- package/src/ts/components/accessorybox.ts +164 -67
- package/src/ts/components/directive.ts +53 -24
- package/src/ts/components/option-handle.ts +121 -54
- package/src/ts/components/placeholder.ts +70 -32
- package/src/ts/components/popup/empty-state.ts +68 -32
- package/src/ts/components/popup/loading-state.ts +70 -30
- package/src/ts/components/popup/popup.ts +0 -1
- package/src/ts/components/searchbox.ts +185 -46
- package/src/ts/components/selectbox.ts +309 -30
- package/src/ts/core/base/adapter.ts +158 -77
- package/src/ts/core/base/fenwick.ts +147 -0
- package/src/ts/core/base/lifecycle.ts +118 -35
- package/src/ts/core/base/model.ts +94 -36
- package/src/ts/core/base/recyclerview.ts +0 -1
- package/src/ts/core/base/view.ts +54 -23
- package/src/ts/core/base/virtual-recyclerview.ts +360 -278
- package/src/ts/core/model-manager.ts +162 -81
- package/src/ts/core/search-controller.ts +164 -91
- package/src/ts/global.ts +1 -1
- package/src/ts/index.ts +1 -1
- package/src/ts/models/group-model.ts +138 -32
- package/src/ts/models/option-model.ts +184 -48
- package/src/ts/services/dataset-observer.ts +72 -10
- package/src/ts/services/ea-observer.ts +87 -10
- package/src/ts/services/effector.ts +181 -32
- package/src/ts/services/refresher.ts +30 -6
- package/src/ts/services/resize-observer.ts +132 -15
- package/src/ts/services/select-observer.ts +115 -50
- package/src/ts/types/utils/ievents.type.ts +6 -1
- package/src/ts/utils/callback-scheduler.ts +112 -34
- package/src/ts/utils/ievents.ts +91 -29
- package/src/ts/utils/selective.ts +330 -61
- package/src/ts/views/group-view.ts +137 -26
- package/src/ts/views/option-view.ts +262 -50
|
@@ -10,42 +10,67 @@ import { Lifecycle } from "./base/lifecycle";
|
|
|
10
10
|
import { ModelManager } from "./model-manager";
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
13
|
+
* Search orchestration layer for Selective's Select UI.
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* -
|
|
18
|
-
* -
|
|
19
|
-
*
|
|
20
|
-
* - Coordinate UI updates via Popup (loading indicator, resize, empty/not-found states)
|
|
15
|
+
* This controller bridges **user-driven search input** (keyword changes / infinite scroll)
|
|
16
|
+
* to either:
|
|
17
|
+
* - **Local filtering**: toggling model visibility flags in-memory, or
|
|
18
|
+
* - **Remote search (AJAX)**: fetching, normalizing, and applying results back into the backing
|
|
19
|
+
* native `<select>` element.
|
|
21
20
|
*
|
|
22
|
-
*
|
|
23
|
-
* -
|
|
24
|
-
* -
|
|
25
|
-
* -
|
|
21
|
+
* ### Responsibilities
|
|
22
|
+
* - Choose search strategy (local vs AJAX) based on {@link AjaxConfig}.
|
|
23
|
+
* - Normalize heterogeneous server response shapes into {@link NormalizedAjaxItem} via {@link parseResponse}.
|
|
24
|
+
* - Track pagination state (page counters, `hasMore`, `isLoading`, current keyword).
|
|
25
|
+
* - Apply remote results into the `<select>` (DOM mutation) and keep selection when requested.
|
|
26
|
+
* - Coordinate transient UI states via {@link Popup} (loading indicator).
|
|
27
|
+
*
|
|
28
|
+
* ### Lifecycle (Strict FSM)
|
|
29
|
+
* - Constructed with references to the native `<select>`, a {@link ModelManager}, and {@link SelectBox}.
|
|
30
|
+
* - Calls {@link Lifecycle.init} immediately during construction (via `initialize()`).
|
|
31
|
+
* - Does **not** mount DOM by itself; it is invoked by higher-level components.
|
|
32
|
+
* - {@link destroy} clears references; further calls should be treated as **no-ops** by consumers.
|
|
33
|
+
*
|
|
34
|
+
* ### Side effects
|
|
35
|
+
* - Local search: mutates `OptionModel.visible` flags (model-layer side effects).
|
|
36
|
+
* - AJAX apply: mutates `<select>` children (`innerHTML`, `appendChild`, dataset, selected state).
|
|
37
|
+
* - UI: calls `popup.showLoading()` / `popup.hideLoading()` when a popup is attached.
|
|
26
38
|
*
|
|
27
39
|
* @extends Lifecycle
|
|
40
|
+
* @see {@link ModelManager}
|
|
41
|
+
* @see {@link AjaxConfig}
|
|
42
|
+
* @see {@link Popup}
|
|
28
43
|
*/
|
|
29
44
|
export class SearchController extends Lifecycle {
|
|
30
|
-
/** Backing native
|
|
45
|
+
/** Backing native `<select>` element providing context and the authoritative option DOM. */
|
|
31
46
|
private select: HTMLSelectElement;
|
|
32
47
|
|
|
33
|
-
/** Model manager providing access to model resources (items, adapter, recycler). */
|
|
48
|
+
/** Model manager providing access to current model resources (items, adapter, recycler). */
|
|
34
49
|
private modelManager: ModelManager<MixedItem, any>;
|
|
35
50
|
|
|
36
|
-
/**
|
|
51
|
+
/**
|
|
52
|
+
* AJAX configuration; when `null`, {@link search} falls back to local filtering.
|
|
53
|
+
* @see {@link setAjax}
|
|
54
|
+
*/
|
|
37
55
|
private ajaxConfig: AjaxConfig | null = null;
|
|
38
56
|
|
|
39
|
-
/**
|
|
57
|
+
/** Abort handle used to cancel an in-flight AJAX request when a newer request starts. */
|
|
40
58
|
private abortController: AbortController | null = null;
|
|
41
59
|
|
|
42
|
-
/**
|
|
60
|
+
/** Optional popup handle used for showing/hiding loading UI during remote operations. */
|
|
43
61
|
private popup: Popup | null = null;
|
|
44
62
|
|
|
45
|
-
/**
|
|
63
|
+
/**
|
|
64
|
+
* SelectBox handle used by custom data builder functions that require Selective context.
|
|
65
|
+
* NOTE: This is a reference; the controller does not own/destroy the SelectBox.
|
|
66
|
+
*/
|
|
46
67
|
private selectBox: SelectBox = null;
|
|
47
68
|
|
|
48
|
-
/**
|
|
69
|
+
/**
|
|
70
|
+
* Remote pagination and loading state.
|
|
71
|
+
* - `currentKeyword` is the last keyword used to compute pagination identity.
|
|
72
|
+
* - `isPaginationEnabled` is inferred from server response shape.
|
|
73
|
+
*/
|
|
49
74
|
private paginationState: PaginationState = {
|
|
50
75
|
currentPage: 0,
|
|
51
76
|
totalPages: 1,
|
|
@@ -56,12 +81,12 @@ export class SearchController extends Lifecycle {
|
|
|
56
81
|
};
|
|
57
82
|
|
|
58
83
|
/**
|
|
59
|
-
*
|
|
60
|
-
*
|
|
84
|
+
* Creates a SearchController bound to a native `<select>` and an existing {@link ModelManager}.
|
|
85
|
+
* Immediately transitions lifecycle `NEW → INITIALIZED` via {@link Lifecycle.init}.
|
|
61
86
|
*
|
|
62
|
-
* @param selectElement -
|
|
63
|
-
* @param modelManager - Manager responsible for
|
|
64
|
-
* @param selectBox - SelectBox handle.
|
|
87
|
+
* @param {HTMLSelectElement} selectElement - Native select element acting as the authoritative data source/target.
|
|
88
|
+
* @param {ModelManager<MixedItem, any>} modelManager - Manager responsible for model resources and rendering refresh.
|
|
89
|
+
* @param {SelectBox} selectBox - SelectBox handle used by configured AJAX data builders.
|
|
65
90
|
*/
|
|
66
91
|
public constructor(selectElement: HTMLSelectElement, modelManager: ModelManager<MixedItem, any>, selectBox: SelectBox) {
|
|
67
92
|
super();
|
|
@@ -69,11 +94,13 @@ export class SearchController extends Lifecycle {
|
|
|
69
94
|
}
|
|
70
95
|
|
|
71
96
|
/**
|
|
72
|
-
*
|
|
97
|
+
* Captures dependencies and starts the controller lifecycle.
|
|
98
|
+
* Intended to be called only from the constructor.
|
|
73
99
|
*
|
|
74
|
-
* @param selectElement -
|
|
75
|
-
* @param modelManager -
|
|
76
|
-
* @param selectBox - SelectBox handle.
|
|
100
|
+
* @param {HTMLSelectElement} selectElement - Native select element.
|
|
101
|
+
* @param {ModelManager<MixedItem, any>} modelManager - Model manager.
|
|
102
|
+
* @param {SelectBox} selectBox - SelectBox handle.
|
|
103
|
+
* @returns {void}
|
|
77
104
|
*/
|
|
78
105
|
private initialize(selectElement: HTMLSelectElement, modelManager: ModelManager<MixedItem, any>, selectBox: SelectBox): void {
|
|
79
106
|
this.select = selectElement;
|
|
@@ -84,24 +111,31 @@ export class SearchController extends Lifecycle {
|
|
|
84
111
|
}
|
|
85
112
|
|
|
86
113
|
/**
|
|
87
|
-
* Indicates whether AJAX
|
|
114
|
+
* Indicates whether remote (AJAX) search is configured.
|
|
88
115
|
*
|
|
89
|
-
* @returns
|
|
116
|
+
* @returns {boolean} `true` when {@link AjaxConfig} is present; otherwise `false`.
|
|
90
117
|
*/
|
|
91
118
|
public isAjax(): boolean {
|
|
92
119
|
return !!this.ajaxConfig;
|
|
93
120
|
}
|
|
94
121
|
|
|
95
122
|
/**
|
|
96
|
-
* Loads specific
|
|
123
|
+
* Loads specific option rows by their values from the server (AJAX-only).
|
|
97
124
|
*
|
|
98
|
-
* Behavior
|
|
99
|
-
* - Uses `ajaxConfig.dataByValues`
|
|
125
|
+
* ### Behavior
|
|
126
|
+
* - Uses `ajaxConfig.dataByValues(values[])` when provided; otherwise builds a default payload:
|
|
127
|
+
* `{ values: "...", load_by_values: "1", ...ajaxConfig.data }`.
|
|
100
128
|
* - Supports GET/POST according to `ajaxConfig.method` (defaults to GET).
|
|
101
|
-
* - Normalizes the response via
|
|
129
|
+
* - Normalizes the response via {@link parseResponse}.
|
|
130
|
+
* - Calls {@link Lifecycle.update} to mark an internal update.
|
|
102
131
|
*
|
|
103
|
-
* @param values -
|
|
104
|
-
* @returns Promise
|
|
132
|
+
* @param {string | string[]} values - One value or a list of values to fetch.
|
|
133
|
+
* @returns {Promise<{ success: boolean; items: NormalizedAjaxItem[]; message?: string }>}
|
|
134
|
+
* Resolves with normalized items on success.
|
|
135
|
+
*
|
|
136
|
+
* @remarks
|
|
137
|
+
* - When AJAX is not configured, resolves with `{ success: false, ... }`.
|
|
138
|
+
* - This method does not mutate the `<select>`; it only returns normalized items.
|
|
105
139
|
*/
|
|
106
140
|
async loadByValues(values: string | string[]): Promise<{ success: boolean; items: NormalizedAjaxItem[]; message?: string }> {
|
|
107
141
|
if (!this.ajaxConfig) {
|
|
@@ -157,10 +191,11 @@ export class SearchController extends Lifecycle {
|
|
|
157
191
|
}
|
|
158
192
|
|
|
159
193
|
/**
|
|
160
|
-
*
|
|
194
|
+
* Partitions the given values into those already present in the current `<select>` options
|
|
195
|
+
* and those missing.
|
|
161
196
|
*
|
|
162
|
-
* @param values - Values to check
|
|
163
|
-
* @returns
|
|
197
|
+
* @param {string[]} values - Values to check.
|
|
198
|
+
* @returns {{ existing: string[]; missing: string[] }} Partitioned result.
|
|
164
199
|
*/
|
|
165
200
|
public checkMissingValues(values: string[]): { existing: string[]; missing: string[] } {
|
|
166
201
|
const allOptions = Array.from(this.select.options);
|
|
@@ -174,26 +209,30 @@ export class SearchController extends Lifecycle {
|
|
|
174
209
|
|
|
175
210
|
/**
|
|
176
211
|
* Configures AJAX settings used for remote searching and pagination.
|
|
212
|
+
* Setting `null` disables AJAX mode and causes {@link search} to use local filtering.
|
|
177
213
|
*
|
|
178
|
-
* @param config - AJAX configuration (endpoint, method, data builders,
|
|
214
|
+
* @param {AjaxConfig | null} config - AJAX configuration (endpoint, method, data builders, keepSelected, ...).
|
|
215
|
+
* @returns {void}
|
|
179
216
|
*/
|
|
180
217
|
public setAjax(config: AjaxConfig | null): void {
|
|
181
218
|
this.ajaxConfig = config;
|
|
182
219
|
}
|
|
183
220
|
|
|
184
221
|
/**
|
|
185
|
-
* Attaches a
|
|
222
|
+
* Attaches a popup instance so the controller can reflect transient UI states
|
|
223
|
+
* during remote operations (e.g., loading indicator).
|
|
186
224
|
*
|
|
187
|
-
* @param popupInstance -
|
|
225
|
+
* @param {Popup} popupInstance - Popup used to show results and loading state.
|
|
226
|
+
* @returns {void}
|
|
188
227
|
*/
|
|
189
228
|
public setPopup(popupInstance: Popup): void {
|
|
190
229
|
this.popup = popupInstance;
|
|
191
230
|
}
|
|
192
231
|
|
|
193
232
|
/**
|
|
194
|
-
* Returns a shallow
|
|
233
|
+
* Returns a shallow snapshot of the current pagination state.
|
|
195
234
|
*
|
|
196
|
-
* @returns
|
|
235
|
+
* @returns {PaginationState} State snapshot (defensive copy).
|
|
197
236
|
*/
|
|
198
237
|
public getPaginationState(): PaginationState {
|
|
199
238
|
return { ...this.paginationState };
|
|
@@ -201,7 +240,9 @@ export class SearchController extends Lifecycle {
|
|
|
201
240
|
|
|
202
241
|
/**
|
|
203
242
|
* Resets pagination counters while preserving whether pagination is enabled.
|
|
204
|
-
* Clears page
|
|
243
|
+
* Clears page/totals/loading flags and the current keyword.
|
|
244
|
+
*
|
|
245
|
+
* @returns {void}
|
|
205
246
|
*/
|
|
206
247
|
public resetPagination(): void {
|
|
207
248
|
this.paginationState = {
|
|
@@ -215,9 +256,13 @@ export class SearchController extends Lifecycle {
|
|
|
215
256
|
}
|
|
216
257
|
|
|
217
258
|
/**
|
|
218
|
-
* Clears the current keyword and
|
|
259
|
+
* Clears the current keyword and restores visibility for all option models (local reset).
|
|
219
260
|
*
|
|
220
|
-
*
|
|
261
|
+
* ### Notes
|
|
262
|
+
* - No network requests are made.
|
|
263
|
+
* - This mutates `OptionModel.visible` for the current model set exposed by {@link ModelManager#getResources}.
|
|
264
|
+
*
|
|
265
|
+
* @returns {void}
|
|
221
266
|
*/
|
|
222
267
|
public clear(): void {
|
|
223
268
|
this.paginationState.currentKeyword = "";
|
|
@@ -236,11 +281,13 @@ export class SearchController extends Lifecycle {
|
|
|
236
281
|
}
|
|
237
282
|
|
|
238
283
|
/**
|
|
239
|
-
* Performs a search
|
|
284
|
+
* Performs a search using the configured strategy.
|
|
285
|
+
* - If {@link AjaxConfig} is present, executes {@link ajaxSearch}.
|
|
286
|
+
* - Otherwise performs local filtering via {@link localSearch}.
|
|
240
287
|
*
|
|
241
|
-
* @param keyword -
|
|
242
|
-
* @param append -
|
|
243
|
-
* @returns
|
|
288
|
+
* @param {string} keyword - Search term.
|
|
289
|
+
* @param {boolean} [append=false] - AJAX mode only: append results (next page) instead of replacing.
|
|
290
|
+
* @returns {Promise<any>} Implementation-specific result object from the underlying strategy.
|
|
244
291
|
*/
|
|
245
292
|
public async search(keyword: string, append: boolean = false): Promise<any> {
|
|
246
293
|
if (this.ajaxConfig) return this.ajaxSearch(keyword, append);
|
|
@@ -248,9 +295,14 @@ export class SearchController extends Lifecycle {
|
|
|
248
295
|
}
|
|
249
296
|
|
|
250
297
|
/**
|
|
251
|
-
* Loads the next page
|
|
298
|
+
* Loads the next page in AJAX mode when pagination is enabled and available.
|
|
299
|
+
*
|
|
300
|
+
* ### Guards (no-ops with error result)
|
|
301
|
+
* - AJAX must be configured.
|
|
302
|
+
* - Must not already be loading.
|
|
303
|
+
* - Pagination must be enabled and `hasMore` must be true.
|
|
252
304
|
*
|
|
253
|
-
* @returns Result of the paginated
|
|
305
|
+
* @returns {Promise<any>} Result of the paginated request, or an error object when not applicable.
|
|
254
306
|
*/
|
|
255
307
|
public async loadMore(): Promise<any> {
|
|
256
308
|
if (!this.ajaxConfig) return { success: false, message: "Ajax not enabled" };
|
|
@@ -263,11 +315,19 @@ export class SearchController extends Lifecycle {
|
|
|
263
315
|
}
|
|
264
316
|
|
|
265
317
|
/**
|
|
266
|
-
* Executes
|
|
267
|
-
* and toggling each option's visibility based on text match.
|
|
318
|
+
* Executes an in-memory search by normalizing the keyword and toggling each option's visibility.
|
|
268
319
|
*
|
|
269
|
-
*
|
|
270
|
-
*
|
|
320
|
+
* ### Matching
|
|
321
|
+
* - Keyword is lowercased and de-accented via {@link Libs.string2normalize}.
|
|
322
|
+
* - Each option uses `OptionModel.textToFind` for matching.
|
|
323
|
+
*
|
|
324
|
+
* ### Side effects
|
|
325
|
+
* - Mutates `OptionModel.visible`.
|
|
326
|
+
* - Calls {@link Lifecycle.update}.
|
|
327
|
+
*
|
|
328
|
+
* @param {string} keyword - Keyword to filter against local options.
|
|
329
|
+
* @returns {Promise<{ success: boolean; hasResults: boolean; isEmpty: boolean }>}
|
|
330
|
+
* Summary result for UI consumers.
|
|
271
331
|
*/
|
|
272
332
|
private async localSearch(keyword: string): Promise<{ success: boolean; hasResults: boolean; isEmpty: boolean }> {
|
|
273
333
|
if (this.compareSearchTrigger(keyword)) this.paginationState.currentKeyword = keyword;
|
|
@@ -302,29 +362,31 @@ export class SearchController extends Lifecycle {
|
|
|
302
362
|
}
|
|
303
363
|
|
|
304
364
|
/**
|
|
305
|
-
*
|
|
306
|
-
* to
|
|
365
|
+
* Determines whether the given keyword differs from the currently tracked keyword.
|
|
366
|
+
* Used to decide whether a new search "session" should reset pagination.
|
|
307
367
|
*
|
|
308
|
-
* @param keyword -
|
|
309
|
-
* @returns
|
|
368
|
+
* @param {string} keyword - Candidate keyword.
|
|
369
|
+
* @returns {boolean} `true` if keyword differs from `paginationState.currentKeyword`.
|
|
310
370
|
*/
|
|
311
371
|
public compareSearchTrigger(keyword: string): boolean {
|
|
312
372
|
return keyword !== this.paginationState.currentKeyword;
|
|
313
373
|
}
|
|
314
374
|
|
|
315
375
|
/**
|
|
316
|
-
* Executes an AJAX-based search with optional appending.
|
|
376
|
+
* Executes an AJAX-based search with optional appending (pagination).
|
|
317
377
|
*
|
|
318
|
-
* Behavior
|
|
319
|
-
* -
|
|
320
|
-
* -
|
|
321
|
-
* -
|
|
322
|
-
* -
|
|
323
|
-
* -
|
|
378
|
+
* ### Behavior
|
|
379
|
+
* - If keyword changed (see {@link compareSearchTrigger}), pagination is reset and `append` is forced to `false`.
|
|
380
|
+
* - Aborts any in-flight request and starts a new one via {@link AbortController}.
|
|
381
|
+
* - Shows/hides loading UI on the attached {@link Popup} if present.
|
|
382
|
+
* - Supports GET/POST based on {@link AjaxConfig.method}; payload is built from {@link AjaxConfig.data}.
|
|
383
|
+
* - Normalizes server response via {@link parseResponse}.
|
|
384
|
+
* - Applies items to the underlying `<select>` via {@link applyAjaxResult}.
|
|
385
|
+
* - Updates pagination state when pagination info is present in the response.
|
|
324
386
|
*
|
|
325
|
-
* @param keyword - Search keyword.
|
|
326
|
-
* @param append - Whether to append results (true = next page)
|
|
327
|
-
* @returns
|
|
387
|
+
* @param {string} keyword - Search keyword.
|
|
388
|
+
* @param {boolean} [append=false] - Whether to append results (true = next page).
|
|
389
|
+
* @returns {Promise<any>} Implementation-specific result object with pagination flags.
|
|
328
390
|
*/
|
|
329
391
|
private async ajaxSearch(keyword: string, append: boolean = false): Promise<any> {
|
|
330
392
|
const cfg = this.ajaxConfig!;
|
|
@@ -411,20 +473,21 @@ export class SearchController extends Lifecycle {
|
|
|
411
473
|
}
|
|
412
474
|
|
|
413
475
|
/**
|
|
414
|
-
* Normalizes various server response shapes into a
|
|
476
|
+
* Normalizes various server response shapes into a consistent {@link ParseResponseResult}.
|
|
415
477
|
*
|
|
416
|
-
* Supported shapes
|
|
417
|
-
* - `{ object: [...], page?, totalPages?, hasMore? }`
|
|
418
|
-
* - `{ data: [...], page?, totalPages?, hasMore? }`
|
|
419
|
-
* - `{ items: [...], pagination: { page, totalPages
|
|
478
|
+
* ### Supported response shapes
|
|
479
|
+
* - `{ object: [...], page?, totalPages?/total_page?, hasMore? }`
|
|
480
|
+
* - `{ data: [...], page?, totalPages?/total_page?, hasMore? }`
|
|
481
|
+
* - `{ items: [...], pagination: { page, totalPages?/total_page?, hasMore? } }`
|
|
420
482
|
* - `[...]` (array of items)
|
|
421
483
|
*
|
|
422
|
-
*
|
|
423
|
-
* -
|
|
424
|
-
* -
|
|
484
|
+
* ### Item normalization rules
|
|
485
|
+
* - Raw DOM nodes (`HTMLOptionElement` / `HTMLOptGroupElement`) are passed through as-is.
|
|
486
|
+
* - Group-like objects are recognized by `type === "optgroup"` or heuristic fields (`isGroup`, `group`, `label`).
|
|
487
|
+
* - Option-like objects are mapped to `{ type: "option", value, text, selected?, data? }`.
|
|
425
488
|
*
|
|
426
|
-
* @param data - Server response (
|
|
427
|
-
* @returns
|
|
489
|
+
* @param {any} data - Server response (unknown shape).
|
|
490
|
+
* @returns {ParseResponseResult} Normalized items with pagination metadata.
|
|
428
491
|
*/
|
|
429
492
|
private parseResponse(data: any): ParseResponseResult {
|
|
430
493
|
let items: any[] = [];
|
|
@@ -493,16 +556,22 @@ export class SearchController extends Lifecycle {
|
|
|
493
556
|
}
|
|
494
557
|
|
|
495
558
|
/**
|
|
496
|
-
* Applies normalized AJAX results to the
|
|
559
|
+
* Applies normalized AJAX results to the backing `<select>` element.
|
|
497
560
|
*
|
|
498
|
-
* Behavior
|
|
499
|
-
* - Optionally preserves existing
|
|
500
|
-
* - Clears existing
|
|
501
|
-
* -
|
|
561
|
+
* ### Behavior
|
|
562
|
+
* - Optionally preserves existing selection values (`keepSelected`).
|
|
563
|
+
* - Clears existing options when `append === false`.
|
|
564
|
+
* - Accepts either normalized items or raw DOM nodes (`HTMLOptionElement` / `HTMLOptGroupElement`).
|
|
565
|
+
* - Populates `dataset` for `data` payload fields on generated nodes.
|
|
502
566
|
*
|
|
503
|
-
*
|
|
504
|
-
*
|
|
505
|
-
*
|
|
567
|
+
* ### DOM side effects
|
|
568
|
+
* - Mutates `<select>`: `innerHTML` (when replacing) and `appendChild` (when adding).
|
|
569
|
+
* - Mutates selection state via `option.selected`.
|
|
570
|
+
*
|
|
571
|
+
* @param {NormalizedAjaxItem[]} items - Normalized items (or raw DOM nodes).
|
|
572
|
+
* @param {boolean} keepSelected - Whether to preserve previously selected options by value.
|
|
573
|
+
* @param {boolean} [append=false] - Append to existing options instead of replacing.
|
|
574
|
+
* @returns {void}
|
|
506
575
|
*/
|
|
507
576
|
public applyAjaxResult(items: NormalizedAjaxItem[], keepSelected: boolean, append: boolean = false): void {
|
|
508
577
|
const select = this.select;
|
|
@@ -574,10 +643,14 @@ export class SearchController extends Lifecycle {
|
|
|
574
643
|
|
|
575
644
|
/**
|
|
576
645
|
* Destroys the controller and clears references.
|
|
646
|
+
* Idempotent: returns early if already in {@link LifecycleState.DESTROYED}.
|
|
647
|
+
*
|
|
648
|
+
* ### Notes
|
|
649
|
+
* - This controller does not own/destroy the linked {@link Popup}, {@link ModelManager}, or {@link SelectBox}.
|
|
650
|
+
* - In-flight requests are not explicitly aborted here; consumers may abort earlier by triggering a new search,
|
|
651
|
+
* or handle cancellation externally.
|
|
577
652
|
*
|
|
578
|
-
*
|
|
579
|
-
* - In-flight requests are not aborted here; consumers should abort if needed before destroy.
|
|
580
|
-
* - The linked Popup/ModelManager exist outside this controller and are not destroyed here.
|
|
653
|
+
* @returns {void}
|
|
581
654
|
*/
|
|
582
655
|
public override destroy(): void {
|
|
583
656
|
if (this.is(LifecycleState.DESTROYED)) {
|
package/src/ts/global.ts
CHANGED
|
@@ -179,5 +179,5 @@ export function rebind(query: string, options: SelectiveOptions = {}): void {
|
|
|
179
179
|
* fx.show();
|
|
180
180
|
*/
|
|
181
181
|
export function effector(element: string | HTMLElement): EffectorInterface {
|
|
182
|
-
return globalThis.GLOBAL_SEUI.effector(element) as
|
|
182
|
+
return globalThis.GLOBAL_SEUI.effector(element) as EffectorInterface;
|
|
183
183
|
}
|
package/src/ts/index.ts
CHANGED
|
@@ -130,7 +130,7 @@ export function rebind(query: string, options: SelectiveOptions = {}): void {
|
|
|
130
130
|
* fx.show();
|
|
131
131
|
*/
|
|
132
132
|
export function effector(element: string | HTMLElement): EffectorInterface {
|
|
133
|
-
return Effector(element) as
|
|
133
|
+
return Effector(element) as EffectorInterface;
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
let domInitialized = false;
|