@cntwg/html-ctrls-lists 0.0.32 → 0.0.33

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,538 @@
1
+ // [v0.2.091-20260510]
2
+
3
+ // === module init block ===
4
+
5
+ const {
6
+ isPlainObject,
7
+ } = require('@ygracs/bsfoc-lib-js');
8
+
9
+ const {
10
+ TItemsListEx,
11
+ } = require('@ygracs/lists-lib-js');
12
+
13
+ const {
14
+ isHTMLElement, isSelectedHTMLElement, isHiddenHTMLElement,
15
+ showHTMLElement, hideHTMLElement,
16
+ selectHTMLElement, unselectHTMLElement,
17
+ markHTMLElementAsCurrent, unmarkCurrentHTMLElement,
18
+ readAsAttrValue, valueToClassList,
19
+ } = require('@cntwg/html-helper');
20
+
21
+ // === module inner block ===
22
+
23
+ /**
24
+ * @typedef {Object} ISearchListElementResultOnFail
25
+ * @property {number} index - element index
26
+ * @property {null} item - found element
27
+ */
28
+
29
+ /**
30
+ * @typedef {Object} ISearchListElementResultOnSuccess
31
+ * @property {number} index - element index
32
+ * @property {any} item - found element
33
+ */
34
+
35
+ /**
36
+ * @typedef {ISearchListElementResultOnFail|ISearchListElementResultOnSuccess} ISearchListElementResult
37
+ */
38
+
39
+ /**
40
+ * Searches an element in a list by a given attributes of that element.
41
+ * @function srchListElementByAttr
42
+ * @param {TItemsListEx} list
43
+ * @param {string} name - target attribute name
44
+ * @param {string} [value=""] - target attribute value
45
+ * @returns {ISearchListElementResult}
46
+ * @inner
47
+ */
48
+ function srchListElementByAttr(list, name, value = '') {
49
+ const _value = readAsAttrValue(value);
50
+ let item = null;
51
+ let index = -1;
52
+ let count = list.count;
53
+ let isACCEPTED = false;
54
+ if (count > 0 && name !== '' && _value !== null) {
55
+ const acceptAnyVal = _value === '';
56
+ for (let i = 0; i < count; i++) {
57
+ item = list.getItem(i);
58
+ if (
59
+ isHTMLElement(item)
60
+ && item.hasAttribute(name)
61
+ && (acceptAnyVal || item.getAttribute(name) === value)
62
+ ) {
63
+ index = i;
64
+ isACCEPTED = true;
65
+ break;
66
+ };
67
+ };
68
+ };
69
+ return isACCEPTED ? { index, item } : { index, item: null };
70
+ };
71
+
72
+ // === module main block ===
73
+
74
+ /**
75
+ * An options set for `THtmlItemsListContainer`-class
76
+ * @typedef {Object} ITHtmlItemsListContainerOptions
77
+ * @property {boolean} [autoHideNewItems=false] - indicates whether to hide
78
+ * a new element
79
+ * @property {boolean} [markCurrentItem=false] - indicates whether to mark
80
+ * a current element
81
+ * @property {string|string[]} [itemBaseClassID] - contains a base class
82
+ * attributes applayed to each a newly added list member
83
+ * @property {number|string} [targetScopeForEID] - \[since v0.0.33] indicates
84
+ * a target scope chosen to select an ID-attribute of the element
85
+ */
86
+ /**
87
+ * A virtual constant meant for support jsdoc notation:
88
+ * @type {ITHtmlItemsListContainerOptions}
89
+ */
90
+ module.exports.ITHtmlItemsListContainerOptions = {};
91
+
92
+ /**
93
+ * @classdesc This class implements an interfaco for a list container
94
+ */
95
+ class THtmlItemsListContainer {
96
+ /** @type {?HTMLElement} */
97
+ #_host;
98
+ /** @type {TItemsListEx} */
99
+ #_items;
100
+ /**
101
+ * A container settings
102
+ * @typedef {Object} THtmlItemsListContainerConfig
103
+ * @property {boolean} autoHideNewItems - indicates whether to hide a new element
104
+ * @property {boolean} markCurrentItem - indicates whether to mark a new element
105
+ * as a current
106
+ * @property {string[]} itemBaseClassID - contains a base class attributes
107
+ * applayed to each a newly added list member
108
+ * @property {number} [targetScopeForEID] - \[since v0.0.33] **reserved**
109
+ */
110
+ /** @type {THtmlItemsListContainerConfig} */
111
+ #_config;
112
+ /**
113
+ * A container status
114
+ * @typedef {Object} statILCont
115
+ * @property {number} curIndex
116
+ * @property {?HTMLElement} curItem
117
+ * @inner
118
+ */
119
+ /** @type {statILCont} */
120
+ #_status;
121
+
122
+ /**
123
+ * Creates an instance of a list container
124
+ * @param {?HTMLElement} host - host element
125
+ * @param {ITHtmlItemsListContainerOptions} [opt] - options
126
+ */
127
+ constructor(host, opt) {
128
+ // check host
129
+ this.#_host = isHTMLElement(host) ? host : null;
130
+ // init items container
131
+ const _items = new TItemsListEx();
132
+ this.#_items = _items;
133
+ // load options
134
+ const _options = isPlainObject(opt) ? opt : {};
135
+ let {
136
+ autoHideNewItems,
137
+ markCurrentItem,
138
+ itemBaseClassID,
139
+ } = _options;
140
+ if (typeof autoHideNewItems !== 'boolean') {
141
+ autoHideNewItems = false;
142
+ // // TODO: next line planned to be removed
143
+ _options.autoHideNewItems = autoHideNewItems;
144
+ };
145
+ if (typeof markCurrentItem !== 'boolean') {
146
+ markCurrentItem = false;
147
+ // // TODO: next line planned to be removed
148
+ _options.markCurrentItem = markCurrentItem;
149
+ };
150
+ itemBaseClassID = valueToClassList(itemBaseClassID, true);
151
+ // // TODO: next line planned to be removed
152
+ _options.itemBaseClassID = itemBaseClassID;
153
+ // init status
154
+ /** @type {statILCont} */
155
+ const _status = {
156
+ curIndex: _items.curIndex,
157
+ curItem: _items.curItem,
158
+ };
159
+ this.#_status = _status;
160
+ // save options
161
+ this.#_config = {
162
+ autoHideNewItems,
163
+ markCurrentItem,
164
+ itemBaseClassID,
165
+ };
166
+ }
167
+
168
+ [Symbol.iterator]() {
169
+ let index = 0;
170
+ return {
171
+ next: () => {
172
+ if (index < this.count) {
173
+ return { done: false, value: this.getItem(index++) };
174
+ } else {
175
+ return { done: true, value: undefined };
176
+ };
177
+ },
178
+ return() {
179
+ return { done: true, value: undefined };
180
+ },
181
+ };
182
+ }
183
+
184
+ /**
185
+ * Contains a Qty of an elements
186
+ * @type {number}
187
+ * @readonly
188
+ */
189
+ get count() {
190
+ return this.#_items.count;
191
+ }
192
+
193
+ /**
194
+ * Contains an index of the current element
195
+ * @type {number}
196
+ * @readonly
197
+ */
198
+ get curIndex() {
199
+ return this.#_items.curIndex;
200
+ }
201
+
202
+ /**
203
+ * Returns a minimum value of an index
204
+ * @type {number}
205
+ * @readonly
206
+ */
207
+ get minIndex() {
208
+ return this.#_items.minIndex;
209
+ }
210
+
211
+ /**
212
+ * Returns a maximum value of an index
213
+ * @type {number}
214
+ * @readonly
215
+ */
216
+ get maxIndex() {
217
+ return this.#_items.maxIndex;
218
+ }
219
+
220
+ /**
221
+ * Returns a value of a previous index
222
+ * @type {number}
223
+ * @readonly
224
+ */
225
+ get prevIndex() {
226
+ return this.#_items.prevIndex;
227
+ }
228
+
229
+ /**
230
+ * Returns a value of a next index
231
+ * @type {number}
232
+ * @readonly
233
+ */
234
+ get nextIndex() {
235
+ return this.#_items.nextIndex;
236
+ }
237
+
238
+ /**
239
+ * Returns an element in the current index
240
+ * @type {?HTMLElement}
241
+ * @readonly
242
+ */
243
+ get curItem() {
244
+ const item = this.#_items.curItem;
245
+ return isHTMLElement(item) ? item : null;
246
+ }
247
+
248
+ /**
249
+ * Clears an instance content.
250
+ * @returns {void}
251
+ */
252
+ clear() {
253
+ this.#_items.clear();
254
+ const _status = this.#_status;
255
+ _status.curIndex = this.curIndex;
256
+ _status.curItem = this.curItem;
257
+ const _host = this.#_host;
258
+ if (_host) _host.innerHTML = '';
259
+ }
260
+
261
+ /**
262
+ * Checks if an instance contains no items.
263
+ * @returns {boolean}
264
+ */
265
+ isEmpty() {
266
+ return this.#_items.isEmpty();
267
+ }
268
+
269
+ /**
270
+ * Checks if an instance contains any items.
271
+ * @returns {boolean}
272
+ */
273
+ isNotEmpty() {
274
+ return this.#_items.isNotEmpty();
275
+ }
276
+
277
+ /**
278
+ * Checks if a given value is a valid index and
279
+ * it fits an index range within an instance.
280
+ * @param {number|string} value - index value
281
+ * @returns {boolean}
282
+ * @deprecated
283
+ * @todo \[since v0.0.31] deprecated. Use
284
+ * {@link THtmlItemsListContainer.checkIndex} instead
285
+ */
286
+ chkIndex(value) {
287
+ return this.#_items.checkIndex(value);
288
+ }
289
+
290
+ /**
291
+ * Checks if a given value is a valid index and
292
+ * it fits an index range within an instance.
293
+ * @since 0.0.31
294
+ * @param {number|string} value - index value
295
+ * @returns {boolean}
296
+ */
297
+ checkIndex(value) {
298
+ return this.#_items.checkIndex(value);
299
+ }
300
+
301
+ /**
302
+ * Checks if a given value is a valid index and
303
+ * it fits an index range within an instance.
304
+ * @param {number|string} value - value to check
305
+ * @param {boolean} [opt=false] - defines a type of result
306
+ * @returns {boolean|number}
307
+ * @deprecated
308
+ * @todo \[since v0.0.31] deprecated. Use
309
+ * {@link THtmlItemsListContainer.checkIndex} or
310
+ * {@link THtmlItemsListContainer.tryIndex} instead
311
+ */
312
+ chkIndexEx(value, opt) {
313
+ return opt ? this.#_items.tryIndex(value) : this.#_items.checkIndex(value);
314
+ }
315
+
316
+ /**
317
+ * Returns an index in case a given value is a valid index value and not exceeds
318
+ * an index range within the list. If failed a `-1` returned
319
+ * @since 0.0.31
320
+ * @param {any} value - value to evaluate
321
+ * @returns {number}
322
+ */
323
+ tryIndex(value) {
324
+ return this.#_items.tryIndex(value);
325
+ }
326
+
327
+ /**
328
+ * Returns an index of a given element.
329
+ * @param {HTMLElement} item - element to search
330
+ * @returns {number}
331
+ * @todo add 2nd param
332
+ * @see TItemsListEx.srchIndex
333
+ */
334
+ srchIndex(item) {
335
+ return isHTMLElement(item) ? this.#_items.srchIndex(item) : -1;
336
+ }
337
+
338
+ /**
339
+ * Returns an index of an element wich has an attribute
340
+ * with a given name and value.
341
+ * @param {string} name - attribute name
342
+ * @param {any} [value=""] - attribute value
343
+ * @returns {number}
344
+ */
345
+ srchIndexByAttr(name, value = '') {
346
+ const _name = typeof name === 'string' ? name.trim() : '';
347
+ const { index } = srchListElementByAttr(this.#_items, _name, value);
348
+ return index;
349
+ };
350
+
351
+ /**
352
+ * Returns an index of an element wich has a given ID.
353
+ * @param {string} value - element ID
354
+ * @returns {number}
355
+ */
356
+ srchIndexByID(value) {
357
+ const { index } = srchListElementByAttr(this.#_items, 'id', value);
358
+ return index;
359
+ };
360
+
361
+ /**
362
+ * Sets a current index.
363
+ * @param {number|string} index - element index
364
+ * @returns {boolean}
365
+ */
366
+ setCurIndex(index) {
367
+ const isSUCCEED = this.#_items.setIndex(index);
368
+ if (isSUCCEED) {
369
+ const markCurrentItem = this.#_config.markCurrentItem;
370
+ const _status = this.#_status;
371
+ if (markCurrentItem && _status.curIndex !== -1) {
372
+ unmarkCurrentHTMLElement(_status.curItem);
373
+ };
374
+ const item = this.getItem(index);
375
+ _status.curIndex = Number(index);
376
+ _status.curItem = item;
377
+ if (markCurrentItem) markHTMLElementAsCurrent(item);
378
+ };
379
+ return isSUCCEED;
380
+ }
381
+
382
+ /**
383
+ * Resets a current index.
384
+ * @returns {void}
385
+ */
386
+ rstCurIndex() {
387
+ const _status = this.#_status;
388
+ if (this.#_config.markCurrentItem && _status.curIndex !== -1) {
389
+ unmarkCurrentHTMLElement(_status.curItem);
390
+ };
391
+ this.#_items.rstIndex();
392
+ _status.curIndex = this.#_items.curIndex;
393
+ _status.curItem = this.curItem;
394
+ }
395
+
396
+ /**
397
+ * Returns an item addressed by a given index.
398
+ * @param {number|string} index - element index
399
+ * @returns {?HTMLElement}
400
+ */
401
+ getItem(index) {
402
+ const item = this.#_items.getItem(index);
403
+ return isHTMLElement(item) ? item : null;
404
+ }
405
+
406
+ /**
407
+ * Returns an item wich has an attribute with a given name and value.
408
+ * @param {string} name - attribute name
409
+ * @param {any} [value=""] - attribute value
410
+ * @returns {?HTMLElement}
411
+ */
412
+ getItemByAttr(name, value = '') {
413
+ const _name = typeof name === 'string' ? name.trim() : '';
414
+ const { item } = srchListElementByAttr(this.#_items, _name, value);
415
+ return item;
416
+ }
417
+
418
+ /**
419
+ * Returns an item wich has a given ID.
420
+ * @param {string} value - element ID
421
+ * @returns {?HTMLElement}
422
+ */
423
+ getItemByID(value) {
424
+ const { item } = srchListElementByAttr(this.#_items, 'id', value);
425
+ return item;
426
+ }
427
+
428
+ /**
429
+ * Adds an item to an instance.
430
+ * @param {HTMLElement} item - some element
431
+ * @param {boolean} [opt=false] - indicates whether to correct a current index
432
+ * @returns {number}
433
+ */
434
+ addItem(item, opt) {
435
+ const forceCI = typeof opt === 'boolean' ? opt : false;
436
+ const index = (
437
+ isHTMLElement(item)
438
+ ? this.#_items.addItemEx(item, false)
439
+ : -1
440
+ );
441
+ const isSUCCEED = index !== -1;
442
+ if (isSUCCEED) {
443
+ const { autoHideNewItems, itemBaseClassID } = this.#_config;
444
+ if (autoHideNewItems) hideHTMLElement(item);
445
+ if (itemBaseClassID.length > 0) item.classList.add(...itemBaseClassID);
446
+ if (forceCI) this.setCurIndex(index);
447
+ const _host = this.#_host;
448
+ if (_host) _host.append(item);
449
+ };
450
+ return isSUCCEED ? index : -1;
451
+ }
452
+
453
+ /**
454
+ * Deletes an item from an instance.
455
+ * @param {number|string} index - element index
456
+ * @param {any} [opt]
457
+ * @param {boolean} [optEx=true]
458
+ * @returns {boolean}
459
+ */
460
+ delItem(index, opt, optEx) {
461
+ const _items = this.#_items;
462
+ const item = _items.delItemEx(index, opt);
463
+ const isSUCCEED = item !== undefined;
464
+ if (isSUCCEED) {
465
+ if (this.#_host && isHTMLElement(item)) item.remove();
466
+ const doProcEx = typeof optEx === 'boolean' ? optEx : true;
467
+ if (doProcEx) {
468
+ const index = _items.curIndex;
469
+ if (index === -1) {
470
+ this.rstCurIndex();
471
+ } else {
472
+ this.setCurIndex(index);
473
+ };
474
+ };
475
+ };
476
+ return isSUCCEED;
477
+ }
478
+
479
+ /**
480
+ * Selects an item addressed by a given index.
481
+ * @param {number|string} index - element index
482
+ * @param {boolean} [opt=false] - indicates whether to correct a current index
483
+ * @returns {boolean}
484
+ */
485
+ selectItem(index, opt) {
486
+ const forceCI = typeof opt === 'boolean' ? opt : false;
487
+ const isSUCCEED = selectHTMLElement(this.#_items.getItem(index));
488
+ if (isSUCCEED && forceCI) this.setCurIndex(index);
489
+ return isSUCCEED;
490
+ }
491
+
492
+ /**
493
+ * Unselects an item addressed by a given index.
494
+ * @param {number|string} index - element index
495
+ * @returns {boolean}
496
+ */
497
+ unselectItem(index) {
498
+ return unselectHTMLElement(this.#_items.getItem(index));
499
+ }
500
+
501
+ /**
502
+ * Hides an item addressed by a given index.
503
+ * @param {number|string} index - element index
504
+ * @returns {boolean}
505
+ */
506
+ hideItem(index) {
507
+ return hideHTMLElement(this.#_items.getItem(index));
508
+ }
509
+
510
+ /**
511
+ * Shows an item addressed by a given index.
512
+ * @param {number|string} index - element index
513
+ * @returns {boolean}
514
+ */
515
+ showItem(index) {
516
+ return showHTMLElement(this.#_items.getItem(index));
517
+ }
518
+
519
+ /**
520
+ * Checks whether an item is selected.
521
+ * @param {number|string} index - element index
522
+ * @returns {boolean}
523
+ */
524
+ isSelectedItem(index) {
525
+ return isSelectedHTMLElement(this.#_items.getItem(index));
526
+ }
527
+
528
+ /**
529
+ * Checks whether an item is hidden.
530
+ * @param {number|string} index - element index
531
+ * @returns {boolean}
532
+ */
533
+ isHiddenItem(index) {
534
+ return isHiddenHTMLElement(this.#_items.getItem(index));
535
+ }
536
+
537
+ };
538
+ module.exports.THtmlItemsListContainer = THtmlItemsListContainer;
@@ -0,0 +1,85 @@
1
+ /**
2
+ * An options set for `THtmlItemsListController`-class
3
+ */
4
+ export type IHtmlItemsListControllerOptions = {
5
+ /**
6
+ * - indicates whether to hide a new element
7
+ */
8
+ autoHideNewItems?: boolean;
9
+ /**
10
+ * - indicates whether to mark a current element
11
+ */
12
+ markCurrentItem?: boolean;
13
+ /**
14
+ * - contains a base class
15
+ * attributes applayed to each a newly added list member
16
+ */
17
+ itemBaseClassID?: string | string[];
18
+ /**
19
+ * - indicates a target scope chosen to select an ID-attribute of the element
20
+ * @since 0.0.33
21
+ */
22
+ targetScopeForEID?: string | number;
23
+ /**
24
+ * - indicates whether to show stubs if empty
25
+ */
26
+ showStubsIfEmpty?: boolean;
27
+ /**
28
+ * - indicates whether a selection of the elements group is allowed
29
+ */
30
+ allowGroupSelection?: boolean;
31
+ /**
32
+ * - indicates whether locking of an element selection is allowed
33
+ */
34
+ allowSelectionLocks?: boolean;
35
+ /**
36
+ * - stub elements options
37
+ */
38
+ stubs?: IStubItemsSetOptions | undefined;
39
+ };
40
+ export const IHtmlItemsListControllerOptions: IHtmlItemsListControllerOptions;
41
+ import type { IStubItemsSetOptions } from "./lists-stubs";
42
+
43
+ /**
44
+ * This class enhanced a capabilities implemented
45
+ * in the `THtmlItemsListContainer` class
46
+ */
47
+ export class THtmlItemsListController extends THtmlItemsListContainer {
48
+ /**
49
+ * Creates a new instance of the class.
50
+ */
51
+ constructor(host: HTMLElement | null, opt?: IHtmlItemsListControllerOptions);
52
+ /**
53
+ * Returns a list of the selected elements
54
+ */
55
+ get SelectedItems(): HTMLElement[];
56
+ /**
57
+ * Returns a `THtmlStubItemsSet` instance
58
+ */
59
+ get StubItems(): THtmlStubItemsSet;
60
+ /**
61
+ * Indicates whether a selection is locked
62
+ */
63
+ get isSelectionLocked(): boolean;
64
+ /**
65
+ * Locks an element selection.
66
+ */
67
+ lockItemsSelection(): void;
68
+ /**
69
+ * Unlocks an element selection.
70
+ */
71
+ unlockItemsSelection(): void;
72
+ /**
73
+ * Deletes an element from an instance members.
74
+ * @fires THtmlItemsListController#list-clear
75
+ * @fires THtmlItemsListController#item-removed
76
+ */
77
+ delItem(index: number | string, opt?: any): boolean;
78
+ /**
79
+ * Sets a callback function to handle event.
80
+ */
81
+ on(name: string, evnt: Function): void;
82
+ #private;
83
+ }
84
+ import { THtmlItemsListContainer } from "./list-cont";
85
+ import { THtmlStubItemsSet } from "./lists-stubs";