@syncfusion/ej2-lists 23.1.42 → 23.2.4

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.
@@ -1,1187 +0,0 @@
1
- import { ListView, ItemCreatedArgs, classNames, Fields, UISelectedItem } from './list-view';
2
- import { EventHandler, append, isNullOrUndefined, detach, removeClass, addClass, compile, formatUnit } from '@syncfusion/ej2-base';
3
- import { debounce } from '@syncfusion/ej2-base';
4
- import { ListBase } from '../common/list-base';
5
- import { DataManager } from '@syncfusion/ej2-data';
6
-
7
- /**
8
- * ElementContext
9
- */
10
- export interface ElementContext extends HTMLElement {
11
- context: { [key: string]: string | object };
12
- }
13
-
14
- const listElementCount: number = 1.5;
15
- const windowElementCount: number = 3;
16
-
17
- export class Virtualization {
18
- constructor(instance: ListView) {
19
- this.listViewInstance = instance;
20
- }
21
-
22
- // eslint-disable-next-line
23
- private listViewInstance: any;
24
- private headerData: DataSource;
25
- private templateData: DataSource;
26
- private topElementHeight: number;
27
- private bottomElementHeight: number;
28
- public listItemHeight: number;
29
- private domItemCount: number;
30
- private expectedDomItemCount: number;
31
- private scrollPosition: number;
32
- private onVirtualScroll: EventListener;
33
- private updateUl: EventListener;
34
- private checkListWrapper: Node;
35
- private iconCssWrapper: Node;
36
- public uiFirstIndex: number;
37
- private uiLastIndex: number;
38
- private totalHeight: number;
39
- private topElement: HTMLElement;
40
- private bottomElement: HTMLElement;
41
- private activeIndex: number;
42
- private uiIndices: { [key: string]: number[] };
43
- private listDiff: number;
44
- private elementDifference: number = 0;
45
-
46
- /**
47
- * For internal use only.
48
- *
49
- * @private
50
- */
51
-
52
- public isNgTemplate(): boolean {
53
- return !isNullOrUndefined(this.listViewInstance.templateRef) && typeof this.listViewInstance.templateRef !== 'string';
54
- }
55
-
56
- /**
57
- * Checks if the platform is a Vue and its template property is a function type.
58
- *
59
- * @returns {boolean} indicating the result of the check
60
- */
61
-
62
- private isVueFunctionTemplate(): boolean {
63
- return this.listViewInstance.isVue && typeof this.listViewInstance.template === 'function';
64
- }
65
-
66
- /**
67
- * For internal use only.
68
- *
69
- * @private
70
- */
71
-
72
- public uiVirtualization(): void {
73
- this.wireScrollEvent(false);
74
- const curViewDS: { [key: string]: object; }[] = this.listViewInstance.curViewDS as { [key: string]: object; }[];
75
- const firstDs: { [key: string]: object }[] = curViewDS.slice(0, 1);
76
- this.listViewInstance.ulElement = this.listViewInstance.curUL = ListBase.createList(
77
- // eslint-disable-next-line
78
- this.listViewInstance.createElement, firstDs as any, this.listViewInstance.listBaseOption, null, this.listViewInstance);
79
- this.listViewInstance.contentContainer = this.listViewInstance.createElement('div', { className: classNames.container });
80
- this.listViewInstance.element.appendChild(this.listViewInstance.contentContainer);
81
- this.listViewInstance.contentContainer.appendChild(this.listViewInstance.ulElement);
82
- this.listItemHeight = this.listViewInstance.ulElement.firstElementChild.getBoundingClientRect().height;
83
- this.expectedDomItemCount = this.ValidateItemCount(10000);
84
- this.domItemCount = this.ValidateItemCount(Object.keys(this.listViewInstance.curViewDS).length);
85
- this.uiFirstIndex = 0;
86
- this.uiLastIndex = this.domItemCount - 1;
87
- const otherDs: { [key: string]: object; }[] = curViewDS.slice(1, this.domItemCount);
88
- const listItems: HTMLElement[] = ListBase.createListItemFromJson(
89
- // eslint-disable-next-line
90
- this.listViewInstance.createElement, otherDs as any, this.listViewInstance.listBaseOption, null, null, this.listViewInstance);
91
- append(listItems, this.listViewInstance.ulElement);
92
- this.listViewInstance.liCollection = <HTMLElement[] & NodeListOf<HTMLLIElement>>
93
- this.listViewInstance.curUL.querySelectorAll('li');
94
- this.topElement = this.listViewInstance.createElement('div');
95
- this.listViewInstance.ulElement.insertBefore(this.topElement, this.listViewInstance.ulElement.firstElementChild);
96
- this.bottomElement = this.listViewInstance.createElement('div');
97
- this.listViewInstance.ulElement.insertBefore(this.bottomElement, null);
98
- this.totalHeight = (Object.keys(curViewDS).length * this.listItemHeight) - (this.domItemCount * this.listItemHeight);
99
- this.topElement.style.height = 0 + 'px';
100
- this.bottomElement.style.height = this.totalHeight + 'px';
101
- this.topElementHeight = 0;
102
- this.bottomElementHeight = this.totalHeight;
103
- this.listDiff = 0;
104
- this.uiIndicesInitialization();
105
- }
106
-
107
- private wireScrollEvent(destroy: boolean): void {
108
- if (!destroy) {
109
- if (this.listViewInstance.isWindow) {
110
- this.onVirtualScroll = this.onVirtualUiScroll.bind(this);
111
- window.addEventListener('scroll', this.onVirtualScroll);
112
- } else {
113
- EventHandler.add(this.listViewInstance.element, 'scroll', this.onVirtualUiScroll, this);
114
- }
115
- } else {
116
- if (this.listViewInstance.isWindow === true) {
117
- window.removeEventListener('scroll', this.onVirtualScroll);
118
- window.removeEventListener('scroll', this.updateUl);
119
- }
120
- else {
121
- EventHandler.remove(this.listViewInstance.element, 'scroll', this.onVirtualUiScroll);
122
- EventHandler.remove(this.listViewInstance.element, 'scroll', this.updateUlContainer);
123
- }
124
- }
125
- }
126
-
127
- private updateUlContainer(e: Event): void {
128
- let listDiff: number;
129
- const virtualElementContainer: HTMLElement = this.listViewInstance.ulElement.querySelector('.' + classNames.virtualElementContainer);
130
- if (isNullOrUndefined(this.listViewInstance.liElementHeight)) {
131
- this.listViewInstance.updateLiElementHeight();
132
- }
133
-
134
- if (this.listViewInstance.isWindow) {
135
- // eslint-disable-next-line
136
- listDiff = Math.round((e as any).target.documentElement.scrollTop / this.listViewInstance.liElementHeight) - 2;
137
- } else {
138
- // eslint-disable-next-line
139
- listDiff = Math.round((e as any).target.scrollTop / this.listViewInstance.liElementHeight) - 2;
140
- }
141
- if (((listDiff - 1) * this.listViewInstance.liElementHeight) < 0) {
142
- virtualElementContainer.style.top = '0px';
143
- } else {
144
- virtualElementContainer.style.top = (listDiff) * this.listViewInstance.liElementHeight + 'px';
145
- }
146
- }
147
-
148
- private ValidateItemCount(dataSourceLength: number): number {
149
- const height: number = parseFloat(formatUnit(this.listViewInstance.height));
150
- let itemCount: number;
151
- if (this.listViewInstance.isWindow) {
152
- itemCount = Math.round((window.innerHeight / this.listItemHeight) * windowElementCount);
153
- } else {
154
- if (typeof this.listViewInstance.height === 'string' && this.listViewInstance.height.indexOf('%') !== -1) {
155
- // eslint-disable-next-line max-len
156
- itemCount = Math.round((this.listViewInstance.element.getBoundingClientRect().height / this.listItemHeight) * listElementCount);
157
- } else {
158
- itemCount = Math.round((height / this.listItemHeight) * listElementCount);
159
- }
160
- }
161
- if (itemCount > dataSourceLength) {
162
- itemCount = dataSourceLength;
163
- }
164
- return itemCount;
165
- }
166
-
167
- private uiIndicesInitialization(): void {
168
- this.uiIndices = { 'activeIndices': [], 'disabledItemIndices': [], 'hiddenItemIndices': [] };
169
- const data: DataSource[] = this.listViewInstance.curViewDS as DataSource[];
170
- for (let i: number = 0; i < data.length; i++) {
171
- if (this.listViewInstance.showCheckBox && data[i as number][this.listViewInstance.fields.isChecked]) {
172
- this.uiIndices.activeIndices.push(i);
173
- }
174
- // eslint-disable-next-line
175
- if (!isNullOrUndefined((data[i] as any)[this.listViewInstance.fields.enabled]) &&
176
- !data[i as number][this.listViewInstance.fields.enabled]) {
177
- // eslint-disable-next-line
178
- (this.uiIndices.disabledItemIndices.push(i)) as any;
179
- }
180
- }
181
- if (this.isNgTemplate()) {
182
- const items: ElementContext[] = this.listViewInstance.element.querySelectorAll('.' + classNames.listItem);
183
- for (let index: number = 0; index < items.length; index++) {
184
- items[index as number].context = this.listViewInstance.viewContainerRef.get(index).context;
185
- }
186
- }
187
- }
188
-
189
- public refreshItemHeight(): void {
190
- if (this.listViewInstance.curViewDS.length) {
191
- const curViewDS: { [key: string]: object; }[] = this.listViewInstance.curViewDS as { [key: string]: object; }[];
192
- this.listItemHeight = (this.topElement.nextSibling as HTMLElement).getBoundingClientRect().height;
193
- this.totalHeight = (Object.keys(curViewDS).length * this.listItemHeight) - (this.domItemCount * this.listItemHeight);
194
- this.bottomElementHeight = this.totalHeight;
195
- this.bottomElement.style.height = this.totalHeight + 'px';
196
- }
197
- }
198
-
199
- private getscrollerHeight(startingHeight: number): number {
200
- return this.listViewInstance.isWindow ? (((pageYOffset - startingHeight) <= 0) ? 0 :
201
- (pageYOffset - startingHeight)) : ((this.listViewInstance.element.scrollTop - startingHeight) <= 0) ? 0 :
202
- (this.listViewInstance.element.scrollTop - startingHeight);
203
- }
204
-
205
- private onVirtualUiScroll(e: Event): void {
206
- let startingHeight: number;
207
- if (this.listViewInstance.isWindow) {
208
- startingHeight = this.listViewInstance.ulElement.getBoundingClientRect().top -
209
- document.documentElement.getBoundingClientRect().top;
210
- } else {
211
- startingHeight = this.listViewInstance.headerEle ? this.listViewInstance.headerEle.getBoundingClientRect().height : 0;
212
- }
213
- this.scrollPosition = isNullOrUndefined(this.scrollPosition) ? 0 : this.scrollPosition;
214
- const scroll: number = this.getscrollerHeight(startingHeight);
215
- this.topElementHeight = this.listItemHeight * Math.floor(scroll / this.listItemHeight);
216
- this.bottomElementHeight = this.totalHeight - this.topElementHeight;
217
- [this.topElementHeight, this.bottomElementHeight] = scroll <= this.totalHeight ?
218
- [this.topElementHeight, this.bottomElementHeight] : [this.totalHeight, 0];
219
- if (this.topElementHeight !== parseFloat(this.topElement.style.height)) {
220
- this.topElement.style.height = this.topElementHeight + 'px';
221
- this.bottomElement.style.height = this.bottomElementHeight + 'px';
222
- if (scroll > this.scrollPosition) {
223
- const listDiff: number = Math.round(((this.topElementHeight / this.listItemHeight) - this.listDiff));
224
- if (listDiff > (this.expectedDomItemCount + 5)) {
225
- this.onLongScroll(listDiff, true);
226
- } else {
227
- this.onNormalScroll(listDiff, true);
228
- }
229
- } else {
230
- const listDiff: number = Math.round((this.listDiff - (this.topElementHeight / this.listItemHeight)));
231
- if (listDiff > (this.expectedDomItemCount + 5)) {
232
- this.onLongScroll(listDiff, false);
233
- } else {
234
- this.onNormalScroll(listDiff, false);
235
- }
236
- }
237
- }
238
- this.listDiff = Math.round(this.topElementHeight / this.listItemHeight);
239
- if (typeof this.listViewInstance.onUIScrolled === 'function') {
240
- this.listViewInstance.onUIScrolled();
241
- }
242
- this.scrollPosition = scroll;
243
- }
244
-
245
- private onLongScroll(listDiff: number, isScrollingDown: boolean): void {
246
- let index: number = isScrollingDown ? (this.uiFirstIndex + listDiff) : (this.uiFirstIndex - listDiff);
247
- const elements: HTMLElement[] = this.listViewInstance.ulElement.querySelectorAll('li');
248
- for (let i: number = 0; i < elements.length; i++) {
249
- this.updateUI(elements[i as number], index);
250
- index++;
251
- }
252
- this.uiLastIndex = isScrollingDown ? (this.uiLastIndex + listDiff) : (this.uiLastIndex - listDiff);
253
- this.uiFirstIndex = isScrollingDown ? (this.uiFirstIndex + listDiff) : (this.uiFirstIndex - listDiff);
254
- }
255
-
256
- private onNormalScroll(listDiff: number, isScrollingDown: boolean): void {
257
- if (isScrollingDown) {
258
- for (let i: number = 0; i < listDiff; i++) {
259
- const index: number = ++this.uiLastIndex;
260
- this.updateUI(this.topElement.nextElementSibling as HTMLElement, index, this.bottomElement);
261
- this.uiFirstIndex++;
262
- }
263
- } else {
264
- for (let i: number = 0; i < listDiff; i++) {
265
- const index: number = --this.uiFirstIndex;
266
- const target: HTMLElement = this.topElement.nextSibling as HTMLElement;
267
- this.updateUI(this.bottomElement.previousElementSibling as HTMLElement, index, target);
268
- this.uiLastIndex--;
269
- }
270
- }
271
- }
272
-
273
- private updateUiContent(element: HTMLElement, index: number): void {
274
- // eslint-disable-next-line
275
- const curViewDs: { [key: string]: any; }[] = this.listViewInstance.curViewDS as DataSource[];
276
- if (typeof (this.listViewInstance.dataSource as string[])[0] === 'string' ||
277
- typeof (this.listViewInstance.dataSource as number[])[0] === 'number') {
278
- element.dataset.uid = ListBase.generateId();
279
- element.getElementsByClassName(classNames.listItemText)[0].innerHTML =
280
- (this.listViewInstance.curViewDS as string[] | number[])[index as number].toString();
281
- } else {
282
- // eslint-disable-next-line
283
- element.dataset.uid = (curViewDs[index][this.listViewInstance.fields.id]) as any ?
284
- // eslint-disable-next-line
285
- (curViewDs[index][this.listViewInstance.fields.id]) as any : (ListBase.generateId() as any);
286
- element.getElementsByClassName(classNames.listItemText)[0].innerHTML =
287
- // eslint-disable-next-line
288
- (curViewDs[index][this.listViewInstance.fields.text]) as any;
289
- }
290
- if (this.listViewInstance.showIcon) {
291
- if (element.querySelector('.' + classNames.listIcon)) {
292
- detach(element.querySelector('.' + classNames.listIcon));
293
- }
294
- if ((this.listViewInstance.curViewDS[index as number] as { [key: string]: object; })[this.listViewInstance.fields.iconCss]) {
295
- const textContent: Element = element.querySelector('.' + classNames.textContent);
296
- const target: Element = this.listViewInstance.createElement('div', {
297
- className: classNames.listIcon + ' ' +
298
- (this.listViewInstance.curViewDS[index as number] as { [key: string]: object; })[this.listViewInstance.fields.iconCss]
299
- });
300
- textContent.insertBefore(target, element.querySelector('.' + classNames.listItemText));
301
- }
302
- }
303
- if (this.listViewInstance.showCheckBox && this.listViewInstance.fields.groupBy) {
304
- if (!this.checkListWrapper) {
305
- this.checkListWrapper = this.listViewInstance.curUL.querySelector('.' + classNames.checkboxWrapper).cloneNode(true);
306
- }
307
- const textContent: Element = element.querySelector('.' + classNames.textContent);
308
- if ((this.listViewInstance.curViewDS[index as number] as { [key: string]: object; }).isHeader) {
309
- if (element.querySelector('.' + classNames.checkboxWrapper)) {
310
- element.classList.remove(classNames.checklist);
311
- textContent.classList.remove(classNames.checkbox);
312
- detach(element.querySelector('.' + classNames.checkboxWrapper));
313
- }
314
- } else {
315
- if (!element.querySelector('.' + classNames.checkboxWrapper)) {
316
- element.classList.add(classNames.checklist);
317
- textContent.classList.add(classNames.checkbox);
318
- textContent.insertBefore(this.checkListWrapper.cloneNode(true), element.querySelector('.' + classNames.listItemText));
319
- }
320
- }
321
- }
322
- }
323
- private changeElementAttributes(element: Element, index: number): void {
324
- element.classList.remove(classNames.disable);
325
- if (this.uiIndices.disabledItemIndices.length && this.uiIndices.disabledItemIndices.indexOf(index) !== -1) {
326
- element.classList.add(classNames.disable);
327
- }
328
- (element as HTMLElement).style.display = '';
329
- if (this.uiIndices.hiddenItemIndices.length && this.uiIndices.hiddenItemIndices.indexOf(index) !== -1) {
330
- (element as HTMLElement).style.display = 'none';
331
- }
332
- if (this.listViewInstance.showCheckBox) {
333
- const checklistElement: Element = element.querySelector('.' + classNames.checkboxWrapper);
334
- element.classList.remove(classNames.selected);
335
- element.classList.remove(classNames.focused);
336
- if (checklistElement) {
337
- checklistElement.removeAttribute('aria-checked');
338
- checklistElement.firstElementChild.classList.remove(classNames.checked);
339
- }
340
- if (this.uiIndices.activeIndices.length && this.uiIndices.activeIndices.indexOf(index) !== -1 &&
341
- !this.listViewInstance.curUL.querySelector(classNames.selected)) {
342
- element.classList.add(classNames.selected);
343
- checklistElement.firstElementChild.classList.add(classNames.checked);
344
- checklistElement.setAttribute('aria-checked', 'true');
345
- if (this.activeIndex === index) {
346
- element.classList.add(classNames.focused);
347
- }
348
- }
349
- } else {
350
- element.classList.remove(classNames.selected);
351
- element.removeAttribute('aria-selected');
352
- if (!isNullOrUndefined(this.activeIndex) && this.activeIndex === index &&
353
- !this.listViewInstance.curUL.querySelector(classNames.selected)) {
354
- element.classList.add(classNames.selected);
355
- element.setAttribute('aria-selected', 'true');
356
- }
357
- }
358
- if (this.listViewInstance.fields.groupBy) {
359
- if ((this.listViewInstance.curViewDS as { [key: string]: object; }[])[index as number].isHeader) {
360
- if (element.classList.contains(classNames.listItem)) {
361
- element.classList.remove(classNames.listItem);
362
- element.setAttribute('role', 'group');
363
- element.classList.add(classNames.groupListItem);
364
- }
365
- } else {
366
- if (element.classList.contains(classNames.groupListItem)) {
367
- element.classList.remove(classNames.groupListItem);
368
- element.setAttribute('role', 'listitem');
369
- element.classList.add(classNames.listItem);
370
- }
371
- }
372
- }
373
- }
374
-
375
- private findDSAndIndexFromId(
376
- ds: DataSource[] | string[] | number[], fields: Fields | Element): DataSource {
377
- const resultJSON: { [key: string]: object | number } = {};
378
- fields = this.listViewInstance.getElementUID(fields);
379
- if (!isNullOrUndefined(fields)) {
380
- (ds as { [key: string]: object; }[]).some((data: { [key: string]: object; }, index: number) => {
381
- if (((fields as { [key: string]: object; })[this.listViewInstance.fields.id] &&
382
- // eslint-disable-next-line
383
- (fields as { [key: string]: any; })[this.listViewInstance.fields.id]
384
- // eslint-disable-next-line
385
- === (data[this.listViewInstance.fields.id] && data[this.listViewInstance.fields.id] as any) || fields === data)) {
386
- resultJSON.index = index;
387
- resultJSON.data = data;
388
- return true;
389
- } else {
390
- return false;
391
- }
392
- });
393
- }
394
-
395
- return resultJSON as DataSource;
396
- }
397
-
398
- public getSelectedItems(): UISelectedItem {
399
- if (!isNullOrUndefined(this.activeIndex) || (this.listViewInstance.showCheckBox && this.uiIndices.activeIndices.length)) {
400
- const dataCollection: string[] | { [key: string]: object; }[] = [];
401
- const textCollection: string[] = [];
402
- if (typeof (this.listViewInstance.dataSource as string[])[0] === 'string' ||
403
- typeof (this.listViewInstance.dataSource as number[])[0] === 'number') {
404
- const curViewDS: string[] | number[] = this.listViewInstance.curViewDS as string[] | number[];
405
- if (this.listViewInstance.showCheckBox) {
406
- const indices: number[] = this.uiIndices.activeIndices;
407
- for (let i: number = 0; i < indices.length; i++) {
408
- (dataCollection as string[]).push((curViewDS as string[])[indices[i as number]]);
409
- }
410
- return {
411
- text: dataCollection as string[],
412
- // eslint-disable-next-line
413
- data: dataCollection as any,
414
- index: this.uiIndices.activeIndices.map((index: number) =>
415
- (this.listViewInstance.dataSource as string[]).indexOf((curViewDS as string[])[index as number]))
416
- };
417
- } else {
418
- return {
419
- text: curViewDS[this.activeIndex],
420
- data: curViewDS[this.activeIndex],
421
- index: (this.listViewInstance.dataSource as string[]).indexOf((curViewDS as string[])[this.activeIndex])
422
- };
423
- }
424
- } else {
425
- const curViewDS: { [key: string]: object | string }[] = this.listViewInstance.curViewDS as { [key: string]: object; }[];
426
- const text: string = this.listViewInstance.fields.text;
427
- if (this.listViewInstance.showCheckBox) {
428
- const indexArray: number[] = this.uiIndices.activeIndices;
429
- for (let i: number = 0; i < indexArray.length; i++) {
430
- textCollection.push((curViewDS[indexArray[i as number]] as { [key: string]: string; })[`${text}`]);
431
- // eslint-disable-next-line
432
- (dataCollection as { [key: string]: any; }[]).push(curViewDS[indexArray[i]] as DataSource);
433
- }
434
- // eslint-disable-next-line
435
- const dataSource: { [key: string]: any; }[] =
436
- this.listViewInstance.dataSource instanceof DataManager
437
- ? curViewDS : this.listViewInstance.dataSource;
438
- return {
439
- text: textCollection,
440
- // eslint-disable-next-line
441
- data: dataCollection as any,
442
- index: this.uiIndices.activeIndices.map((index: number) =>
443
- dataSource.indexOf(curViewDS[index as number] as DataSource))
444
- };
445
- } else {
446
- // eslint-disable-next-line
447
- const dataSource: { [key: string]: any; }[] =
448
- this.listViewInstance.dataSource instanceof DataManager
449
- ? curViewDS : this.listViewInstance.dataSource;
450
- return {
451
- text: curViewDS[this.activeIndex][this.listViewInstance.fields.text] as string,
452
- // eslint-disable-next-line
453
- data: curViewDS[this.activeIndex] as any,
454
- index: dataSource.indexOf(curViewDS[this.activeIndex])
455
- };
456
- }
457
- }
458
- } else {
459
- return undefined;
460
- }
461
- }
462
-
463
- public selectItem(obj: Fields | HTMLElement | Element): void {
464
- // eslint-disable-next-line
465
- const resutJSON: { [key: string]: any | number } = this.findDSAndIndexFromId(this.listViewInstance.curViewDS, obj);
466
- if (Object.keys(resutJSON).length) {
467
- const isSelected: boolean = this.activeIndex === resutJSON.index;
468
- let isChecked: boolean;
469
- this.activeIndex = resutJSON.index as number;
470
- if (this.listViewInstance.showCheckBox) {
471
- if (this.uiIndices.activeIndices.indexOf(resutJSON.index as number) === -1) {
472
- isChecked = true;
473
- this.uiIndices.activeIndices.push(resutJSON.index as number);
474
- } else {
475
- isChecked = false;
476
- this.uiIndices.activeIndices.splice(this.uiIndices.activeIndices.indexOf(resutJSON.index as number), 1);
477
- }
478
- if (this.listViewInstance.curUL.querySelector('.' + classNames.focused)) {
479
- this.listViewInstance.curUL.querySelector('.' + classNames.focused).classList.remove(classNames.focused);
480
- }
481
- }
482
- if (this.listViewInstance.getLiFromObjOrElement(obj)) {
483
- if (this.listViewInstance.showCheckBox) {
484
- this.listViewInstance.setCheckboxLI(this.listViewInstance.getLiFromObjOrElement(obj));
485
- } else {
486
- this.listViewInstance.setSelectLI(this.listViewInstance.getLiFromObjOrElement(obj));
487
- }
488
- } else {
489
- // eslint-disable-next-line
490
- let eventArgs: { [key: string]: any; };
491
- if (typeof (this.listViewInstance.dataSource as string[])[0] === 'string' ||
492
- typeof (this.listViewInstance.dataSource as number[])[0] === 'number') {
493
- eventArgs = {
494
- text: (this.listViewInstance.curViewDS as number[] | string[])[this.activeIndex],
495
- data: (this.listViewInstance.curViewDS as number[] | string[])[this.activeIndex],
496
- index: this.activeIndex
497
- };
498
- } else {
499
- const curViewDS: { [key: string]: object; }[] = this.listViewInstance.curViewDS as { [key: string]: object; }[];
500
- eventArgs = {
501
- text: curViewDS[this.activeIndex][this.listViewInstance.fields.text],
502
- data: curViewDS[this.activeIndex],
503
- index: this.activeIndex
504
- };
505
- }
506
- if (this.listViewInstance.showCheckBox) {
507
- eventArgs.isChecked = isChecked;
508
- this.listViewInstance.trigger('select', eventArgs);
509
- } else if (!isSelected) {
510
- this.listViewInstance.removeSelect();
511
- this.listViewInstance.trigger('select', eventArgs);
512
- }
513
- }
514
- } else if (isNullOrUndefined(obj) && !this.listViewInstance.showCheckBox) {
515
- this.listViewInstance.removeSelect();
516
- this.activeIndex = undefined;
517
- }
518
- }
519
-
520
- public enableItem(obj: Fields | HTMLElement | Element): void {
521
- // eslint-disable-next-line
522
- const resutJSON: { [key: string]: any | number } = this.findDSAndIndexFromId(this.listViewInstance.curViewDS, obj);
523
- if (Object.keys(resutJSON).length) {
524
- this.uiIndices.disabledItemIndices.splice(this.uiIndices.disabledItemIndices.indexOf(resutJSON.index as number), 1);
525
- }
526
- }
527
-
528
- public disableItem(obj: Fields | HTMLElement | Element): void {
529
- // eslint-disable-next-line
530
- const resutJSON: { [key: string]: any | number } = this.findDSAndIndexFromId(this.listViewInstance.curViewDS, obj);
531
- if (Object.keys(resutJSON).length && this.uiIndices.disabledItemIndices.indexOf(resutJSON.index as number) === -1) {
532
- this.uiIndices.disabledItemIndices.push(resutJSON.index as number);
533
- }
534
- }
535
- public showItem(obj: Fields | HTMLElement | Element): void {
536
- // eslint-disable-next-line
537
- const resutJSON: { [key: string]: any | number } = this.findDSAndIndexFromId(this.listViewInstance.curViewDS, obj);
538
- if (Object.keys(resutJSON).length) {
539
- this.uiIndices.hiddenItemIndices.splice(this.uiIndices.hiddenItemIndices.indexOf(resutJSON.index as number), 1);
540
- }
541
- }
542
-
543
- public hideItem(obj: Fields | HTMLElement | Element): void {
544
- // eslint-disable-next-line
545
- const resutJSON: { [key: string]: any | number } = this.findDSAndIndexFromId(this.listViewInstance.curViewDS, obj);
546
- if (Object.keys(resutJSON).length && this.uiIndices.hiddenItemIndices.indexOf(resutJSON.index as number) === -1) {
547
- this.uiIndices.hiddenItemIndices.push(resutJSON.index as number);
548
- }
549
- }
550
-
551
- public removeItem(obj: HTMLElement | Element | Fields): void {
552
- let dataSource: DataSource;
553
- const curViewDS: DataSource[] = this.listViewInstance.curViewDS;
554
- // eslint-disable-next-line
555
- const resutJSON: { [key: string]: any | number } = this.findDSAndIndexFromId(curViewDS, obj);
556
- // eslint-disable-next-line
557
- if (Object.keys(resutJSON).length) {
558
- dataSource = resutJSON.data as DataSource;
559
- if (curViewDS[(resutJSON.index as number) - 1] &&
560
- curViewDS[(resutJSON.index as number) - 1].isHeader &&
561
- ((curViewDS[(resutJSON.index as number) - 1])
562
- .items as { [key: string]: any; }[]).length === 1) {
563
- this.removeUiItem((resutJSON.index as number) - 1);
564
- this.removeUiItem((resutJSON.index as number) - 1);
565
- } else {
566
- this.removeUiItem((resutJSON.index as number));
567
- }
568
- }
569
- const listDataSource: DataSource[] = this.listViewInstance.dataSource instanceof DataManager
570
- ? this.listViewInstance.localData : this.listViewInstance.dataSource;
571
- const index: number = listDataSource.indexOf(dataSource);
572
- if (index !== -1) {
573
- listDataSource.splice(index, 1);
574
- this.listViewInstance.setViewDataSource(listDataSource);
575
- }
576
- // recollect all the list item into collection
577
-
578
- this.listViewInstance.liCollection =
579
- <HTMLElement[] & NodeListOf<HTMLLIElement>>this.listViewInstance.curUL.querySelectorAll('li');
580
-
581
- }
582
-
583
- // eslint-disable-next-line
584
- public setCheckboxLI(li: HTMLElement | Element, e?: MouseEvent | KeyboardEvent | FocusEvent): void {
585
- const index: number = Array.prototype.indexOf.call(this.listViewInstance.curUL.querySelectorAll('li'), li) + this.uiFirstIndex;
586
- this.activeIndex = Array.prototype.indexOf.call(this.listViewInstance.curUL.querySelectorAll('li'), li) + this.uiFirstIndex;
587
- if (li.classList.contains(classNames.selected)) {
588
- if (this.uiIndices.activeIndices.indexOf(index) === -1) {
589
- this.uiIndices.activeIndices.push(index);
590
- }
591
- } else {
592
- this.uiIndices.activeIndices.splice(this.uiIndices.activeIndices.indexOf(index), 1);
593
- }
594
- }
595
-
596
- // eslint-disable-next-line
597
- public setSelectLI(li: HTMLElement | Element, e?: MouseEvent | KeyboardEvent | FocusEvent): void {
598
- this.activeIndex = Array.prototype.indexOf.call(this.listViewInstance.curUL.querySelectorAll('li'), li) + this.uiFirstIndex;
599
- }
600
- public checkedItem(checked: boolean): void {
601
- if (checked) {
602
- this.uiIndices.activeIndices = [];
603
- this.activeIndex = undefined;
604
- const data: DataSource[] = this.listViewInstance.curViewDS as DataSource[];
605
- for (let index: number = 0; index < data.length; index++) {
606
- if (!data[index as number].isHeader) {
607
- this.uiIndices.activeIndices.push(index);
608
- }
609
- }
610
-
611
- } else {
612
- this.activeIndex = undefined;
613
- this.uiIndices.activeIndices = [];
614
- }
615
-
616
- }
617
-
618
- private addUiItem(index: number): void {
619
- // virtually new add list item based on the scollbar position
620
- // if the scroll bar is at the top, just pretend the new item has been added since no UI
621
- // change is required for the item that has been added at last but when scroll bar is at the bottom
622
- // just detach top and inject into bottom to mimic new item is added
623
- const curViewDs: DataSource[] = this.listViewInstance.curViewDS as DataSource[];
624
- this.changeUiIndices(index, true);
625
- if (this.activeIndex && this.activeIndex >= index) {
626
- this.activeIndex++;
627
- }
628
- if (this.listViewInstance.showCheckBox &&
629
- (curViewDs[index as number] as { [key: string]: object; })[this.listViewInstance.fields.isChecked]) {
630
- this.uiIndices.activeIndices.push(index);
631
- }
632
- if (!parseFloat(this.bottomElement.style.height) && !parseFloat(this.topElement.style.height)) {
633
- this.bottomElement.style.height = parseFloat(this.bottomElement.style.height) + this.listItemHeight + 'px';
634
- }
635
- if (parseFloat(this.bottomElement.style.height)) {
636
- const liItem: HTMLElement = this.listViewInstance.curUL.lastElementChild.previousSibling as HTMLElement;
637
- const target: HTMLElement = this.listViewInstance.getLiFromObjOrElement(curViewDs[index + 1]) ||
638
- this.listViewInstance.getLiFromObjOrElement(curViewDs[index + 2]);
639
- if (target) {
640
- this.bottomElement.style.height = parseFloat(this.bottomElement.style.height) + this.listItemHeight + 'px';
641
- this.updateUI(liItem, index, target);
642
- }
643
- } else {
644
- const liItem: HTMLElement = this.listViewInstance.curUL.firstElementChild.nextSibling as HTMLElement;
645
- let target: HTMLElement;
646
- if ((Object.keys(this.listViewInstance.curViewDS).length - 1) === index) {
647
- target = this.listViewInstance.curUL.lastElementChild as HTMLElement;
648
- } else {
649
- target = this.listViewInstance.getLiFromObjOrElement(curViewDs[index + 1]) ||
650
- this.listViewInstance.getLiFromObjOrElement(curViewDs[index + 2]);
651
- }
652
- this.topElement.style.height = parseFloat(this.topElement.style.height) + this.listItemHeight + 'px';
653
- this.uiFirstIndex++;
654
- this.uiLastIndex++;
655
- if (target) {
656
- this.updateUI(liItem, index, target);
657
- if (this.listViewInstance.isWindow === true) {
658
- window.scrollTo(0, (pageYOffset + this.listItemHeight));
659
- }
660
- else {
661
- this.listViewInstance.element.scrollTop += this.listItemHeight;
662
- }
663
- }
664
- }
665
- this.totalHeight += this.listItemHeight;
666
- this.listDiff = Math.round(parseFloat(this.topElement.style.height) / this.listItemHeight);
667
- }
668
-
669
- private removeUiItem(index: number): void {
670
- this.totalHeight -= this.listItemHeight;
671
- const curViewDS: DataSource = (this.listViewInstance.curViewDS as { [key: string]: object; }[])[index as number];
672
- const liItem: HTMLElement = this.listViewInstance.getLiFromObjOrElement(curViewDS);
673
- (this.listViewInstance.curViewDS as { [key: string]: object; }[]).splice(index, 1);
674
- if (this.activeIndex && this.activeIndex >= index) {
675
- this.activeIndex--;
676
- }
677
- if (liItem) {
678
- if (this.domItemCount > Object.keys(this.listViewInstance.curViewDS).length) {
679
- detach(liItem);
680
- this.domItemCount--;
681
- this.uiLastIndex--;
682
- this.totalHeight = 0;
683
- } else {
684
- if (liItem.classList.contains(classNames.disable)) {
685
- liItem.classList.remove(classNames.disable);
686
- this.uiIndices.disabledItemIndices.splice(this.uiIndices.disabledItemIndices.indexOf(index), 1);
687
- }
688
- if (liItem.style.display === 'none') {
689
- liItem.style.display = '';
690
- this.uiIndices.hiddenItemIndices.splice(this.uiIndices.hiddenItemIndices.indexOf(index), 1);
691
- }
692
- if (this.listViewInstance.showCheckBox && liItem.classList.contains(classNames.selected)) {
693
- this.listViewInstance.removeSelect();
694
- this.uiIndices.activeIndices.splice(this.uiIndices.activeIndices.indexOf(index), 1);
695
- const checklistElement: Element = liItem.querySelector('.' + classNames.checkboxWrapper);
696
- checklistElement.removeAttribute('aria-checked');
697
- checklistElement.firstElementChild.classList.remove(classNames.checked);
698
- if (liItem.classList.contains(classNames.focused)) {
699
- liItem.classList.remove(classNames.focused);
700
- this.activeIndex = undefined;
701
- }
702
- } else if (liItem.classList.contains(classNames.selected)) {
703
- this.listViewInstance.removeSelect();
704
- this.activeIndex = undefined;
705
- }
706
- if (!parseFloat(this.bottomElement.style.height) && !parseFloat(this.topElement.style.height)) {
707
- this.updateUI(liItem, this.uiLastIndex, this.bottomElement);
708
- } else if (parseFloat(this.bottomElement.style.height)) {
709
- this.bottomElement.style.height = parseFloat(this.bottomElement.style.height) - this.listItemHeight + 'px';
710
- this.updateUI(liItem, this.uiLastIndex, this.bottomElement);
711
- } else {
712
- this.topElement.style.height = parseFloat(this.topElement.style.height) - this.listItemHeight + 'px';
713
- this.updateUI(liItem, (this.uiFirstIndex - 1), this.topElement.nextSibling as HTMLElement);
714
- this.uiLastIndex--;
715
- this.uiFirstIndex--;
716
- }
717
- }
718
- }
719
- this.changeUiIndices(index, false);
720
- this.listDiff = Math.round(parseFloat(this.topElement.style.height) / this.listItemHeight);
721
- }
722
-
723
- private changeUiIndices(index: number, increment: boolean): void {
724
- const keys: string[] = Object.keys(this.uiIndices);
725
- for (let ind: number = 0; ind < keys.length; ind++) {
726
- this.uiIndices[keys[ind as number]] = this.uiIndices[keys[ind as number]].map((i: number) => {
727
- if (i >= index) {
728
- return increment ? ++i : --i;
729
- } else {
730
- return i;
731
- }
732
- });
733
- }
734
- }
735
-
736
- public addItem(data: DataSource[], fields: Fields, dataSource: DataSource[]): void {
737
- for (let i: number = 0; i < data.length; i++) {
738
- const currentItem: { [key: string]: object; } = data[i as number];
739
- // push the given data to main data array
740
- dataSource.push(currentItem);
741
- // recalculate all the group data or other datasource related things
742
- this.listViewInstance.setViewDataSource(dataSource);
743
- // render list items for first time due to no datasource present earlier
744
- if (!this.domItemCount) {
745
- // fresh rendering for first time
746
- if ((this.listViewInstance.template || this.listViewInstance.groupTemplate) && !this.isNgTemplate()) {
747
- this.listViewInstance.listBaseOption.template = null;
748
- this.listViewInstance.listBaseOption.groupTemplate = null;
749
- this.listViewInstance.listBaseOption.itemCreated = this.createUIItem.bind(this);
750
- }
751
- this.uiVirtualization();
752
- // when expected expected DOM count doesn't meet the condition we need to create and inject new item into DOM
753
- } else if (this.domItemCount < this.expectedDomItemCount) {
754
- const ds: DataSource = this.listViewInstance.findItemFromDS(dataSource, fields);
755
-
756
- if (ds instanceof Array) {
757
- if (this.listViewInstance.ulElement) {
758
- let index: number = (this.listViewInstance.curViewDS as DataSource[]).indexOf(currentItem);
759
- // inject new list item into DOM
760
- this.createAndInjectNewItem(currentItem, index);
761
-
762
- // check for group header item
763
- const curViewDS: DataSource =
764
- (this.listViewInstance.curViewDS as DataSource[])[index - 1];
765
- if (curViewDS && curViewDS.isHeader && (curViewDS.items as DataSource[]).length === 1) {
766
- // target group item index in datasource
767
- --index;
768
- // inject new group header into DOM for previously created list item
769
- this.createAndInjectNewItem(curViewDS, index);
770
- }
771
- }
772
- // recollect all the list item into collection
773
- this.listViewInstance.liCollection =
774
- <HTMLElement[] & NodeListOf<HTMLLIElement>>this.listViewInstance.curUL.querySelectorAll('li');
775
- }
776
- } else {
777
- // eslint-disable-next-line
778
- const index: number = (this.listViewInstance.curViewDS as { [key: string]: any; }[]).indexOf(currentItem);
779
- // virtually new add list item based on the scollbar position
780
- this.addUiItem(index);
781
- // check for group header item needs to be added
782
- const curViewDS: DataSource = (this.listViewInstance.curViewDS as DataSource[])[index - 1];
783
- if (curViewDS && curViewDS.isHeader && (curViewDS.items as DataSource[]).length === 1) {
784
- this.addUiItem(index - 1);
785
- }
786
- }
787
- }
788
- }
789
-
790
- private createAndInjectNewItem(itemData: DataSource, index: number): void {
791
- // generate li item for given datasource
792
- let target: HTMLElement;
793
- const li: HTMLElement[] = ListBase.createListItemFromJson(
794
- this.listViewInstance.createElement,
795
- // eslint-disable-next-line
796
- [itemData] as any,
797
- this.listViewInstance.listBaseOption,
798
- null,
799
- null,
800
- this.listViewInstance);
801
- // check for target element whether to insert before last item or group item
802
- if ((Object.keys(this.listViewInstance.curViewDS).length - 1) === index) {
803
- target = this.listViewInstance.curUL.lastElementChild as HTMLElement;
804
- } else {
805
- // target group header's first child item to append its header
806
- target = this.listViewInstance.getLiFromObjOrElement(this.listViewInstance.curViewDS[index + 1]) ||
807
- this.listViewInstance.getLiFromObjOrElement(this.listViewInstance.curViewDS[index + 2]);
808
- }
809
- if (this.listViewInstance.fields.groupBy && this.listViewInstance.curViewDS[index + 1] && this.listViewInstance.curViewDS[index + 1].isHeader) {
810
- let targetEle: HTMLElement = this.listViewInstance.getLiFromObjOrElement(this.listViewInstance.curViewDS[index - 1]);
811
- if (targetEle) {
812
- target = targetEle.nextElementSibling as HTMLElement;
813
- }
814
- }
815
- // insert before the target element
816
- this.listViewInstance.ulElement.insertBefore(li[0], target);
817
- // increment internal DOM count, last index count for new element
818
- this.domItemCount++;
819
- if (this.bottomElementHeight <= 0) {
820
- this.uiLastIndex++;
821
- }
822
- // recalculate the current item height, to avoid jumpy scroller
823
- this.refreshItemHeight();
824
- }
825
-
826
- public createUIItem(args: ItemCreatedArgs): void {
827
- const virtualTemplate: string = this.listViewInstance.template;
828
- const template: HTMLElement = this.listViewInstance.createElement('div');
829
- let commonTemplate: string = '<div class="e-text-content" role="presentation"> ' +
830
- '<span class="e-list-text"> ${' + this.listViewInstance.fields.text + '} </span></div>';
831
- if (this.listViewInstance.isReact) {
832
- commonTemplate = null;
833
- }
834
- if (this.listViewInstance.showCheckBox) {
835
- // eslint-disable-next-line
836
- (this.listViewInstance as any).renderCheckbox(args);
837
- if ((!isNullOrUndefined(this.listViewInstance.virtualCheckBox)) &&
838
- (!isNullOrUndefined(this.listViewInstance.virtualCheckBox.outerHTML))) {
839
- const div: HTMLElement = document.createElement('div');
840
- div.innerHTML = this.listViewInstance.template || commonTemplate;
841
- if (div.children && div.children[0]) {
842
- div.children[0].classList.add('e-checkbox');
843
- if (this.listViewInstance.checkBoxPosition === 'Left') {
844
- div.children[0].classList.add('e-checkbox-left');
845
- }
846
- else {
847
- div.children[0].classList.add('e-checkbox-right');
848
- }
849
- if (this.listViewInstance.checkBoxPosition === 'Left') {
850
- div.children[0].insertBefore(this.listViewInstance.virtualCheckBox, (div.childNodes[0] as HTMLElement).children[0]);
851
- } else {
852
- div.children[0].appendChild(this.listViewInstance.virtualCheckBox);
853
- }
854
- this.listViewInstance.template = div.innerHTML;
855
- }
856
- }
857
- if (this.isVueFunctionTemplate()) return;
858
- template.innerHTML = this.listViewInstance.template;
859
- this.listViewInstance.template = virtualTemplate;
860
- } else {
861
- if (this.isVueFunctionTemplate()) return;
862
- template.innerHTML = this.listViewInstance.template || commonTemplate;
863
- }
864
- // eslint-disable-next-line
865
- const templateElements: any = template.getElementsByTagName('*');
866
- const groupTemplate: HTMLElement = this.listViewInstance.createElement('div');
867
- if (this.listViewInstance.fields.groupBy) {
868
- groupTemplate.innerHTML = this.listViewInstance.groupTemplate || commonTemplate;
869
- }
870
- // eslint-disable-next-line
871
- let groupTemplateElements: any = groupTemplate.getElementsByTagName('*');
872
- if (args.curData.isHeader) {
873
- this.headerData = args.curData;
874
- }
875
- this.templateData = args.curData.isHeader ? (args.curData as { [key: string]: any[]; }).items[0] as DataSource :
876
- args.curData;
877
- if (!this.listViewInstance.isReact || (typeof this.listViewInstance.template == "string" && !args.item.classList.contains("e-list-group-item")) ||
878
- (typeof this.listViewInstance.groupTemplate == "string" && args.item.classList.contains("e-list-group-item"))) {
879
- args.item.innerHTML = '';
880
- }
881
- (<ElementContext>args.item).context = { data: args.curData, nodes: { flatTemplateNodes: [], groupTemplateNodes: [] } };
882
- for (let i: number = 0; i < templateElements.length; i++) {
883
- this.compileTemplate(templateElements[i as number] as HTMLElement, args.item, false);
884
- }
885
- for (let i: number = 0; i < groupTemplateElements.length; i++) {
886
- this.compileTemplate(groupTemplateElements[i as number] as HTMLElement, args.item, true);
887
- }
888
- (<ElementContext>args.item).context.template = args.curData.isHeader ? template.firstElementChild :
889
- groupTemplate.firstElementChild;
890
- (<ElementContext>args.item).context.type = args.curData.isHeader ? 'flatList' : 'groupList';
891
- const element: HTMLElement = args.curData.isHeader ? groupTemplate : template;
892
- if (element.firstElementChild) {
893
- args.item.insertBefore(element.firstElementChild, null);
894
- }
895
- }
896
-
897
- private compileTemplate(element: HTMLElement, item: HTMLElement, isHeader: boolean): void {
898
- this.textProperty(element, item, isHeader);
899
- this.classProperty(element, item, isHeader);
900
- this.attributeProperty(element, item, isHeader);
901
- }
902
-
903
- private onChange(newData: DataSource, listElement: HTMLElement): void {
904
- (<ElementContext>listElement).context.data = newData;
905
- // eslint-disable-next-line max-len
906
- const groupTemplateNodes: object[] = ((<ElementContext>listElement).context.nodes as { [key: string]: object[] }).groupTemplateNodes;
907
- // eslint-disable-next-line max-len
908
- const flatTemplateNodes: object[] = ((<ElementContext>listElement).context.nodes as { [key: string]: object[] }).flatTemplateNodes;
909
- // eslint-disable-next-line
910
- if (!isNullOrUndefined(newData.isHeader as any) && newData.isHeader as any && (<ElementContext>listElement).context.type as any === 'groupList' as any) {
911
- // eslint-disable-next-line
912
- const element: HTMLElement = listElement.firstElementChild as HTMLElement as any;
913
- detach(listElement.firstElementChild);
914
- listElement.insertBefore((<ElementContext>listElement).context.template as HTMLElement, null);
915
- (<ElementContext>listElement).context.template = element;
916
- (<ElementContext>listElement).context.type = 'flatList';
917
- for (let i: number = 0; i < groupTemplateNodes.length; i++) {
918
- // eslint-disable-next-line
919
- (groupTemplateNodes[i] as { [key: string]: Function }).onChange(newData);
920
- }
921
- } else if (!newData.isHeader && (<ElementContext>listElement).context.type === 'flatList') {
922
- const element: HTMLElement = listElement.firstElementChild as HTMLElement;
923
- detach(listElement.firstElementChild);
924
- listElement.insertBefore((<ElementContext>listElement).context.template as HTMLElement, null);
925
- (<ElementContext>listElement).context.template = element;
926
- (<ElementContext>listElement).context.type = 'groupList';
927
- for (let i: number = 0; i < flatTemplateNodes.length; i++) {
928
- // eslint-disable-next-line
929
- (flatTemplateNodes[i] as { [key: string]: Function }).onChange(newData);
930
- }
931
- } else if (!newData.isHeader) {
932
- for (let i: number = 0; i < flatTemplateNodes.length; i++) {
933
- // eslint-disable-next-line
934
- (flatTemplateNodes[i] as { [key: string]: Function }).onChange(newData);
935
- }
936
- } else {
937
- for (let i: number = 0; i < groupTemplateNodes.length; i++) {
938
- // eslint-disable-next-line
939
- (groupTemplateNodes[i] as { [key: string]: Function }).onChange(newData);
940
- }
941
- }
942
- }
943
-
944
- // eslint-disable-next-line
945
- private updateContextData(listElement: HTMLElement, node: { [key: string]: string | Function | string[] }, isHeader: Boolean): void {
946
- if (isHeader) {
947
- ((<ElementContext>listElement).context.nodes as { [key: string]: object[] }).groupTemplateNodes.push(node);
948
- } else {
949
- ((<ElementContext>listElement).context.nodes as { [key: string]: object[] }).flatTemplateNodes.push(node);
950
- }
951
- }
952
- private classProperty(element: HTMLElement, listElement: HTMLElement, isHeader: boolean): void {
953
- const regex: RegExp = new RegExp('\\${([^}]*)}', 'g');
954
- const resultantOutput: RegExpExecArray[] = [];
955
- let regexMatch: RegExpExecArray;
956
- while (regexMatch !== null) {
957
- const match: RegExpExecArray = regex.exec(element.className);
958
- resultantOutput.push(match);
959
- regexMatch = match;
960
- if (regexMatch === null) {
961
- resultantOutput.pop();
962
- }
963
- }
964
- if (resultantOutput && resultantOutput.length) {
965
- for (let i: number = 0; i < resultantOutput.length; i++) {
966
- const classNameMatch: RegExpExecArray = resultantOutput[i as number];
967
- // eslint-disable-next-line
968
- let classFunction: Function;
969
- if (classNameMatch[1].indexOf('?') !== -1 && classNameMatch[1].indexOf(':') !== -1) {
970
- // tslint:disable-next-line:no-function-constructor-with-string-args
971
- classFunction = new Function('data', 'return ' + classNameMatch[1].replace(/\$/g, 'data.'));
972
- } else {
973
- // tslint:disable-next-line:no-function-constructor-with-string-args
974
- classFunction = new Function('data', 'return ' + 'data.' + classNameMatch[1]);
975
- }
976
- // eslint-disable-next-line
977
- const subNode: { [key: string]: string | Function } = {};
978
- if (isHeader) {
979
- subNode.bindedvalue = classFunction(this.headerData);
980
- } else {
981
- subNode.bindedvalue = classFunction(this.templateData);
982
- }
983
- subNode.onChange = (value: DataSource) => {
984
- if (subNode.bindedvalue) {
985
- removeClass([element], (subNode.bindedvalue as string).split(' ').filter((css: string) => css));
986
- }
987
- const newCss: string = classFunction(value) as string;
988
- if (newCss) {
989
- addClass([element], (newCss).split(' ').filter((css: string) => css));
990
- }
991
- subNode.bindedvalue = newCss;
992
- };
993
- const className: string[] = classNameMatch[0].split(' ');
994
- for (let i: number = 0; i < className.length; i++) { element.classList.remove(className[i as number]); }
995
- if (subNode.bindedvalue) {
996
- addClass([element], (subNode.bindedvalue as string).split(' ').filter((css: string) => css));
997
- }
998
- this.updateContextData(listElement, subNode, isHeader);
999
- }
1000
- }
1001
- }
1002
- private attributeProperty(element: HTMLElement, listElement: HTMLElement, isHeader: boolean): void {
1003
- const attributeNames: string[] = [];
1004
- for (let i: number = 0; i < element.attributes.length; i++) {
1005
- attributeNames.push(element.attributes[i as number].nodeName);
1006
- }
1007
- if (attributeNames.indexOf('class') !== -1) {
1008
- attributeNames.splice(attributeNames.indexOf('class'), 1);
1009
- }
1010
- for (let i: number = 0; i < attributeNames.length; i++) {
1011
- const attributeName: string = attributeNames[i as number];
1012
- const attrNameMatch: RegExpExecArray | string[] = new RegExp('\\${([^}]*)}', 'g').exec(attributeName) || [];
1013
- const attrValueMatch: RegExpExecArray | string[] = new RegExp('\\${([^}]*)}', 'g').exec(element.getAttribute(attributeName))
1014
- || [];
1015
- // eslint-disable-next-line
1016
- let attributeNameFunction: Function;
1017
- // eslint-disable-next-line
1018
- let attributeValueFunction: Function;
1019
- if (attrNameMatch.length || attrValueMatch.length) {
1020
- if (attrNameMatch[1]) {
1021
- // tslint:disable-next-line:no-function-constructor-with-string-args
1022
- attributeNameFunction = new Function('data', 'return ' + 'data.' + attrNameMatch[1]);
1023
- }
1024
- if (attrValueMatch[1]) {
1025
- if (attrValueMatch[1].indexOf('?') !== -1 && attrValueMatch[1].indexOf(':') !== -1) {
1026
- // tslint:disable-next-line:no-function-constructor-with-string-args
1027
- attributeValueFunction = new Function('data', 'return ' + attrValueMatch[1].replace(/\$/g, 'data.'));
1028
- } else {
1029
- // tslint:disable-next-line:no-function-constructor-with-string-args
1030
- attributeValueFunction = new Function('data', 'return ' + 'data.' + attrValueMatch[1]);
1031
- }
1032
- }
1033
- // eslint-disable-next-line @typescript-eslint/ban-types
1034
- const subNode: { [key: string]: string[] | Function | string } = {};
1035
- if (isHeader) {
1036
- subNode.bindedvalue = [attrNameMatch[1] === undefined ? undefined : attributeNameFunction(this.headerData),
1037
- attrValueMatch[1] === undefined ? undefined : attributeValueFunction(this.headerData)];
1038
- } else {
1039
- subNode.bindedvalue = [attrNameMatch[1] === undefined ? undefined : attributeNameFunction(this.templateData),
1040
- attrValueMatch[1] === undefined ? undefined : attributeValueFunction(this.templateData)];
1041
- }
1042
- subNode.attrName = (subNode.bindedvalue as string[])[0] === undefined ?
1043
- attributeName : (subNode.bindedvalue as string[])[0];
1044
- subNode.onChange = (value: DataSource) => {
1045
- const bindedvalue: string = (subNode.bindedvalue as string[])[1] === undefined ?
1046
- element.getAttribute(subNode.attrName as string) : attributeValueFunction(value);
1047
- element.removeAttribute(subNode.attrName as string);
1048
- subNode.attrName = (subNode.bindedvalue as string[])[0] === undefined ? subNode.attrName : attributeNameFunction(value);
1049
- element.setAttribute(subNode.attrName as string, bindedvalue);
1050
- subNode.bindedvalue = [(subNode.bindedvalue as string[])[0] === undefined ? undefined : attributeNameFunction(value),
1051
- (subNode.bindedvalue as string[])[1] === undefined ? undefined : attributeValueFunction(value)];
1052
- };
1053
- const attributeValue: string = (subNode.bindedvalue as string[])[1] === undefined ? element.getAttribute(attributeName) :
1054
- (subNode.bindedvalue as string[])[1];
1055
- element.removeAttribute(attributeName as string);
1056
- element.setAttribute(subNode.attrName as string, attributeValue as string);
1057
- this.updateContextData(listElement, subNode, isHeader);
1058
- }
1059
- }
1060
-
1061
- }
1062
-
1063
- private textProperty(element: HTMLElement, listElement: HTMLElement, isHeader: boolean): void {
1064
- const regex: RegExp = new RegExp('\\${([^}]*)}', 'g');
1065
- const resultantOutput: RegExpExecArray[] = [];
1066
- let regexMatch: RegExpExecArray;
1067
- while (regexMatch !== null) {
1068
- const match: RegExpExecArray = regex.exec(element.innerText);
1069
- resultantOutput.push(match);
1070
- regexMatch = match;
1071
- if (regexMatch === null) {
1072
- resultantOutput.pop();
1073
- }
1074
- }
1075
- const isChildHasTextContent: boolean = Array.prototype.some.call(element.children, (element: HTMLElement) => {
1076
- if (new RegExp('\\${([^}]*)}', 'g').exec(element.innerText)) {
1077
- return true;
1078
-
1079
- } else {
1080
- return false;
1081
- }
1082
- });
1083
- if (resultantOutput && resultantOutput.length && !isChildHasTextContent) {
1084
- for (let i: number = 0; i < resultantOutput.length; i++) {
1085
- const textPropertyMatch: RegExpExecArray = resultantOutput[i as number];
1086
- // eslint-disable-next-line
1087
- const subNode: { [key: string]: string | Function } = {};
1088
- // eslint-disable-next-line
1089
- let textFunction: Function;
1090
- if (textPropertyMatch[1].indexOf('?') !== -1 && textPropertyMatch[1].indexOf(':') !== -1) {
1091
- // tslint:disable-next-line:no-function-constructor-with-string-args
1092
- textFunction = new Function('data', 'return ' + textPropertyMatch[1].replace(/\$/g, 'data.'));
1093
- } else {
1094
- // tslint:disable-next-line:no-function-constructor-with-string-args
1095
- textFunction = new Function('data', 'return ' + 'data.' + textPropertyMatch[1]);
1096
- }
1097
- if (isHeader) {
1098
- subNode.bindedvalue = textFunction(this.headerData);
1099
- } else {
1100
- subNode.bindedvalue = textFunction(this.templateData);
1101
- }
1102
- subNode.onChange = (value: DataSource) => {
1103
- element.innerText = element.innerText.replace(subNode.bindedvalue as string, textFunction(value));
1104
- subNode.bindedvalue = textFunction(value);
1105
- };
1106
- element.innerText = element.innerText.replace(textPropertyMatch[0], subNode.bindedvalue as string);
1107
- this.updateContextData(listElement, subNode, isHeader);
1108
- }
1109
- }
1110
- }
1111
-
1112
- public reRenderUiVirtualization(): void {
1113
- this.wireScrollEvent(true);
1114
- if (this.listViewInstance.contentContainer) {
1115
- detach(this.listViewInstance.contentContainer);
1116
- }
1117
- this.listViewInstance.preRender();
1118
- // resetting the dom count to 0, to avoid edge case of dataSource suddenly becoming zero
1119
- // and then manually adding item using addItem API
1120
- this.domItemCount = 0;
1121
- this.listViewInstance.header();
1122
- this.listViewInstance.setLocalData();
1123
- }
1124
-
1125
- private updateUI(element: HTMLElement, index: number, targetElement?: HTMLElement): void {
1126
- // eslint-disable-next-line @typescript-eslint/ban-types
1127
- const onChange: Function = this.isNgTemplate() ? this.onNgChange : (this.isVueFunctionTemplate()) ? this.onVueChange : this.onChange;
1128
- if (this.listViewInstance.template || this.listViewInstance.groupTemplate) {
1129
- const curViewDS: DataSource = (this.listViewInstance.curViewDS as DataSource[])[index as number];
1130
- // eslint-disable-next-line
1131
- element.dataset.uid = (curViewDS[this.listViewInstance.fields.id]) as any ?
1132
- // eslint-disable-next-line
1133
- (curViewDS[this.listViewInstance.fields.id]) as any : ListBase.generateId() as any;
1134
- onChange(curViewDS, element, this);
1135
- } else {
1136
- this.updateUiContent(element, index);
1137
- }
1138
- this.changeElementAttributes(element, index);
1139
- if (targetElement) {
1140
- this.listViewInstance.ulElement.insertBefore(element, targetElement);
1141
- }
1142
- }
1143
-
1144
- /**
1145
- * Handles the UI change in vue for the list view.
1146
- *
1147
- * @param {DataSource} newData - The new data source for the list view.
1148
- * @param {ElementContext} listElement - The HTML element context for the list view.
1149
- * @param {Virtualization} virtualThis - The virtualization context for the list view.
1150
- */
1151
- private onVueChange(newData: DataSource, listElement: ElementContext, virtualThis: Virtualization): void {
1152
- let liItem: HTMLElement[] = ListBase.createListItemFromJson(virtualThis.listViewInstance.createElement,
1153
- // eslint-disable-next-line
1154
- [newData] as any,
1155
- virtualThis.listViewInstance.listBaseOption, null, null, virtualThis.listViewInstance);
1156
- while (listElement.lastChild) {
1157
- listElement.removeChild(listElement.lastChild);
1158
- }
1159
- listElement.appendChild(liItem[0].firstChild);
1160
- }
1161
-
1162
- private onNgChange(newData: DataSource, listElement: ElementContext, virtualThis: Virtualization): void {
1163
- // compile given target element with template for new data
1164
- // eslint-disable-next-line
1165
- const templateCompiler: Function = compile(virtualThis.listViewInstance.template);
1166
- const resultElement: NodeList = templateCompiler(newData);
1167
- while (listElement.lastChild) {
1168
- listElement.removeChild(listElement.lastChild);
1169
- }
1170
- listElement.appendChild(resultElement[0]);
1171
- }
1172
-
1173
- public getModuleName(): string {
1174
- return 'virtualization';
1175
- }
1176
-
1177
- public destroy(): void {
1178
- this.wireScrollEvent(true);
1179
- this.topElement = null;
1180
- this.bottomElement = null;
1181
- }
1182
- }
1183
-
1184
- interface DataSource {
1185
- [key: string]: object;
1186
- }
1187
-