@syncfusion/ej2-base 24.2.7 → 25.1.35-579988

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.
Files changed (163) hide show
  1. package/.eslintrc.json +2 -1
  2. package/CHANGELOG.md +641 -677
  3. package/{README.md → ReadMe.md} +100 -100
  4. package/dist/ej2-base.umd.min.js +1 -10
  5. package/dist/ej2-base.umd.min.js.map +1 -1
  6. package/dist/es6/ej2-base.es2015.js +178 -1025
  7. package/dist/es6/ej2-base.es2015.js.map +1 -1
  8. package/dist/es6/ej2-base.es5.js +226 -934
  9. package/dist/es6/ej2-base.es5.js.map +1 -1
  10. package/dist/global/ej2-base.min.js +1 -10
  11. package/dist/global/ej2-base.min.js.map +1 -1
  12. package/dist/global/index.d.ts +0 -9
  13. package/dist/ts/ajax.ts +236 -0
  14. package/dist/ts/animation.ts +544 -0
  15. package/dist/ts/base.ts +357 -0
  16. package/dist/ts/browser.ts +387 -0
  17. package/dist/ts/child-property.ts +192 -0
  18. package/dist/ts/component.ts +519 -0
  19. package/dist/ts/dom.ts +488 -0
  20. package/dist/ts/draggable.ts +1155 -0
  21. package/dist/ts/droppable.ts +172 -0
  22. package/dist/ts/event-handler.ts +169 -0
  23. package/dist/ts/internationalization.ts +369 -0
  24. package/dist/ts/intl/date-formatter.ts +317 -0
  25. package/dist/ts/intl/date-parser.ts +426 -0
  26. package/dist/ts/intl/intl-base.ts +1104 -0
  27. package/dist/ts/intl/number-formatter.ts +411 -0
  28. package/dist/ts/intl/number-parser.ts +158 -0
  29. package/dist/ts/intl/parser-base.ts +394 -0
  30. package/dist/ts/keyboard.ts +238 -0
  31. package/dist/ts/l10n.ts +94 -0
  32. package/dist/ts/module-loader.ts +149 -0
  33. package/dist/ts/notify-property-change.ts +726 -0
  34. package/dist/ts/observer.ts +236 -0
  35. package/dist/ts/sanitize-helper.ts +224 -0
  36. package/dist/ts/template-engine.ts +191 -0
  37. package/dist/ts/template.ts +329 -0
  38. package/dist/ts/touch.ts +544 -0
  39. package/dist/ts/util.ts +523 -0
  40. package/dist/ts/validate-lic.ts +0 -0
  41. package/e2e/crypto.js +16 -16
  42. package/e2e/m.protractor.config.js +286 -286
  43. package/e2e/modified-protractor/protractor.config.js +316 -316
  44. package/e2e/protractor.config.js +389 -332
  45. package/helpers/e2e/index.js +3 -3
  46. package/license +10 -10
  47. package/package.json +225 -174
  48. package/src/ajax.d.ts +1 -1
  49. package/src/ajax.js +3 -8
  50. package/src/animation-model.d.ts +41 -41
  51. package/src/animation.d.ts +6 -6
  52. package/src/animation.js +25 -25
  53. package/src/base.d.ts +2 -1
  54. package/src/base.js +9 -7
  55. package/src/component-model.d.ts +16 -16
  56. package/src/component.d.ts +9 -3
  57. package/src/component.js +50 -38
  58. package/src/draggable-model.d.ts +113 -113
  59. package/src/draggable.d.ts +2 -0
  60. package/src/draggable.js +45 -29
  61. package/src/droppable-model.d.ts +23 -23
  62. package/src/droppable.js +19 -19
  63. package/src/event-handler.js +2 -1
  64. package/src/index.d.ts +0 -3
  65. package/src/index.js +0 -3
  66. package/src/intl/date-formatter.js +2 -6
  67. package/src/intl/date-parser.js +1 -20
  68. package/src/intl/intl-base.js +1 -164
  69. package/src/intl/number-formatter.d.ts +3 -0
  70. package/src/intl/number-formatter.js +7 -7
  71. package/src/intl/number-parser.js +1 -0
  72. package/src/keyboard-model.d.ts +16 -16
  73. package/src/keyboard.js +19 -19
  74. package/src/module-loader.d.ts +12 -0
  75. package/src/module-loader.js +11 -0
  76. package/src/notify-property-change.js +3 -2
  77. package/src/observer.js +2 -0
  78. package/src/sanitize-helper.js +5 -0
  79. package/src/template-engine.js +1 -0
  80. package/src/template.js +3 -2
  81. package/src/touch-model.d.ts +39 -39
  82. package/src/touch.js +19 -19
  83. package/src/validate-lic.d.ts +0 -11
  84. package/src/validate-lic.js +1 -259
  85. package/styles/_all.scss +2 -2
  86. package/styles/_bds-dark-definition.scss +15 -0
  87. package/styles/_bds-definition.scss +15 -0
  88. package/styles/_bootstrap-dark-definition.scss +42 -42
  89. package/styles/_bootstrap-definition.scss +42 -42
  90. package/styles/_bootstrap4-definition.scss +11 -11
  91. package/styles/_bootstrap5-dark-definition.scss +9 -9
  92. package/styles/_bootstrap5-definition.scss +8 -8
  93. package/styles/_fabric-dark-definition.scss +42 -42
  94. package/styles/_fabric-definition.scss +42 -42
  95. package/styles/_fluent-dark-definition.scss +9 -9
  96. package/styles/_fluent-definition.scss +9 -9
  97. package/styles/_fluent2-definition.scss +9 -0
  98. package/styles/_fusionnew-dark-definition.scss +8 -8
  99. package/styles/_fusionnew-definition.scss +8 -8
  100. package/styles/_highcontrast-definition.scss +42 -42
  101. package/styles/_highcontrast-light-definition.scss +42 -42
  102. package/styles/_material-dark-definition.scss +48 -48
  103. package/styles/_material-definition.scss +49 -49
  104. package/styles/_material3-dark-definition.scss +14 -14
  105. package/styles/_material3-definition.scss +15 -15
  106. package/styles/_tailwind-dark-definition.scss +15 -15
  107. package/styles/_tailwind-definition.scss +15 -15
  108. package/styles/animation/_all.scss +560 -560
  109. package/styles/bootstrap-dark.css +10 -1
  110. package/styles/bootstrap.css +10 -1
  111. package/styles/bootstrap4.css +10 -1
  112. package/styles/bootstrap5-dark.css +10 -1
  113. package/styles/bootstrap5.css +10 -1
  114. package/styles/common/_all.scss +2 -2
  115. package/styles/common/_core.scss +117 -117
  116. package/styles/common/_mixin.scss +9 -9
  117. package/styles/definition/_bds-dark.scss +1179 -0
  118. package/styles/definition/_bds.scss +1474 -0
  119. package/styles/definition/_bootstrap-dark.scss +219 -219
  120. package/styles/definition/_bootstrap.scss +215 -215
  121. package/styles/definition/_bootstrap4.scss +167 -167
  122. package/styles/definition/_bootstrap5-dark.scss +493 -493
  123. package/styles/definition/_bootstrap5.scss +494 -494
  124. package/styles/definition/_fabric-dark.scss +200 -200
  125. package/styles/definition/_fabric.scss +198 -198
  126. package/styles/definition/_fluent-dark.scss +557 -557
  127. package/styles/definition/_fluent.scss +558 -558
  128. package/styles/definition/_fluent2.scss +2198 -0
  129. package/styles/definition/_fusionnew-dark.scss +362 -362
  130. package/styles/definition/_fusionnew.scss +363 -363
  131. package/styles/definition/_highcontrast-light.scss +193 -193
  132. package/styles/definition/_highcontrast.scss +195 -195
  133. package/styles/definition/_material-dark.scss +198 -198
  134. package/styles/definition/_material.scss +192 -192
  135. package/styles/definition/_material3-dark.scss +710 -710
  136. package/styles/definition/_material3.scss +792 -792
  137. package/styles/definition/_tailwind-dark.scss +488 -488
  138. package/styles/definition/_tailwind.scss +485 -485
  139. package/styles/fabric-dark.css +10 -1
  140. package/styles/fabric.css +10 -1
  141. package/styles/fluent-dark.css +10 -1
  142. package/styles/fluent.css +10 -1
  143. package/styles/highcontrast-light.css +10 -1
  144. package/styles/highcontrast.css +10 -1
  145. package/styles/material-dark.css +10 -1
  146. package/styles/material.css +10 -1
  147. package/styles/material3-dark.css +10 -1
  148. package/styles/material3.css +10 -1
  149. package/styles/offline-theme/material-dark.css +10 -1
  150. package/styles/offline-theme/material.css +10 -1
  151. package/styles/offline-theme/tailwind-dark.css +10 -1
  152. package/styles/offline-theme/tailwind.css +10 -1
  153. package/styles/tailwind-dark.css +10 -1
  154. package/styles/tailwind.css +10 -1
  155. package/.github/PULL_REQUEST_TEMPLATE/Bug.md +0 -60
  156. package/.github/PULL_REQUEST_TEMPLATE/feature.md +0 -42
  157. package/bin/syncfusion-license.js +0 -2
  158. package/dist/ej2-base.min.js +0 -10
  159. package/e2e/index.d.ts +0 -27
  160. package/src/fetch.d.ts +0 -114
  161. package/src/fetch.js +0 -116
  162. package/src/hijri-parser.d.ts +0 -19
  163. package/src/hijri-parser.js +0 -204
@@ -0,0 +1,519 @@
1
+ import { isUndefined, getValue, isNullOrUndefined, setValue, uniqueID, isBlazor } from './util';
2
+ import { ModuleLoader, ModuleDeclaration } from './module-loader';
3
+ import { Base } from './base';
4
+ import { Observer, BoundOptions } from './observer';
5
+ import { ChildProperty } from './child-property';
6
+ import { Property, NotifyPropertyChanges } from './notify-property-change';
7
+ import { onIntlChange, rightToLeft, defaultCulture } from './internationalization';
8
+ import { createElement, addClass, removeClass, ElementProperties, select } from './dom';
9
+ let componentCount: number = 0;
10
+ let lastPageID: number;
11
+ let lastHistoryLen: number = 0;
12
+ export let versionBasedStatePersistence: boolean = false;
13
+
14
+ /**
15
+ * To enable or disable version based statePersistence functionality for all components globally.
16
+ *
17
+ * @param {boolean} status - Optional argument Specifies the status value to enable or disable versionBasedStatePersistence option.
18
+ * @returns {void}
19
+ */
20
+ export function enableVersionBasedPersistence(status: boolean): void {
21
+ versionBasedStatePersistence = status;
22
+ }
23
+ /**
24
+ * Base class for all Essential JavaScript components
25
+ */
26
+ @NotifyPropertyChanges
27
+ export abstract class Component<ElementType extends HTMLElement> extends Base<ElementType> {
28
+
29
+ public element: ElementType;
30
+ // Root component instance.
31
+ // eslint-disable-next-line
32
+ public root: any;
33
+ private randomId: string = uniqueID();
34
+ public ej2StatePersistenceVersion: string;
35
+ /**
36
+ * Enable or disable persisting component's state between page reloads.
37
+ *
38
+ * @default false
39
+ */
40
+ @Property(false)
41
+ public enablePersistence: boolean;
42
+
43
+ /**
44
+ * Enable or disable rendering component in right to left direction.
45
+ *
46
+ * @default false
47
+ */
48
+ @Property()
49
+ public enableRtl: boolean;
50
+ /**
51
+ * Overrides the global culture and localization value for this component. Default global culture is 'en-US'.
52
+ *
53
+ * @default ''
54
+ */
55
+ @Property()
56
+ public locale: string;
57
+ /**
58
+ * string template option for Blazor template rendering
59
+ *
60
+ * @private
61
+ */
62
+ public isStringTemplate: boolean = false;
63
+ // eslint-disable-next-line
64
+ public currentContext: { calls?: Function, args?: any };
65
+ protected needsID: boolean = false;
66
+ protected isReactHybrid: boolean = false;
67
+ protected moduleLoader: ModuleLoader;
68
+ protected localObserver: Observer;
69
+ protected abstract render(): void;
70
+ protected abstract preRender(): void;
71
+ protected abstract getPersistData(): string;
72
+ protected injectedModules: Function[];
73
+ protected mount: Function;
74
+ protected requiredModules(): ModuleDeclaration[] {
75
+ return [];
76
+ }
77
+
78
+ /**
79
+ * Destroys the sub modules while destroying the widget
80
+ *
81
+ * @returns {void} ?
82
+ */
83
+ protected destroy(): void {
84
+ if (this.isDestroyed) { return; }
85
+ if (this.enablePersistence) {
86
+ this.setPersistData();
87
+ this.detachUnloadEvent();
88
+ }
89
+ this.localObserver.destroy();
90
+ if (this.refreshing) { return; }
91
+ removeClass([this.element], ['e-control']);
92
+ this.trigger('destroyed', { cancel: false });
93
+ super.destroy();
94
+ this.moduleLoader.clean();
95
+ onIntlChange.off('notifyExternalChange', this.detectFunction, this.randomId);
96
+ }
97
+ /**
98
+ * Applies all the pending property changes and render the component again.
99
+ *
100
+ * @returns {void} ?
101
+ */
102
+ public refresh(): void {
103
+ this.refreshing = true;
104
+ this.moduleLoader.clean();
105
+ this.destroy();
106
+ this.clearChanges();
107
+ this.localObserver = new Observer(this);
108
+ this.preRender();
109
+ this.injectModules();
110
+ this.render();
111
+ this.refreshing = false;
112
+ }
113
+
114
+ private accessMount(): void {
115
+ if (this.mount && !this.isReactHybrid) {
116
+ this.mount();
117
+ }
118
+ }
119
+ /**
120
+ * Returns the route element of the component
121
+ *
122
+ * @returns {HTMLElement} ?
123
+ */
124
+ public getRootElement(): HTMLElement {
125
+ if (this.isReactHybrid) {
126
+ // eslint-disable-next-line
127
+ return (this as any).actualElement;
128
+ } else {
129
+ return this.element;
130
+ }
131
+ }
132
+ /**
133
+ * Returns the persistence data for component
134
+ *
135
+ * @returns {any} ?
136
+ */
137
+ // eslint-disable-next-line
138
+ public getLocalData(): any {
139
+ const eleId: string = this.getModuleName() + this.element.id;
140
+ if (versionBasedStatePersistence) {
141
+ return window.localStorage.getItem(eleId + this.ej2StatePersistenceVersion);
142
+ } else {
143
+ return window.localStorage.getItem(eleId);
144
+ }
145
+ }
146
+ /**
147
+ * Adding unload event to persist data when enable persistence true
148
+ *
149
+ * @returns {void}
150
+ */
151
+ public attachUnloadEvent(): void {
152
+ this.handleUnload = this.handleUnload.bind(this);
153
+ window.addEventListener('unload', this.handleUnload);
154
+ }
155
+ /**
156
+ * Handling unload event to persist data when enable persistence true
157
+ *
158
+ * @returns {void}
159
+ */
160
+ public handleUnload(): void {
161
+ this.setPersistData();
162
+ }
163
+ /**
164
+ * Removing unload event to persist data when enable persistence true
165
+ *
166
+ * @returns {void}
167
+ */
168
+ public detachUnloadEvent(): void {
169
+ window.removeEventListener('unload', this.handleUnload);
170
+ }
171
+ /**
172
+ * Appends the control within the given HTML element
173
+ *
174
+ * @param {string | HTMLElement} selector - Target element where control needs to be appended
175
+ * @returns {void} ?
176
+ */
177
+ public appendTo(selector?: string | HTMLElement): void {
178
+ if (!isNullOrUndefined(selector) && typeof (selector) === 'string') {
179
+ this.element = <ElementType>select(<string>selector, document);
180
+ } else if (!isNullOrUndefined(selector)) {
181
+ this.element = <ElementType>selector;
182
+ }
183
+ if (!isNullOrUndefined(this.element)) {
184
+ const moduleClass: string = 'e-' + this.getModuleName().toLowerCase();
185
+ addClass([this.element], ['e-control', moduleClass]);
186
+ this.isProtectedOnChange = false;
187
+ if (this.needsID && !this.element.id) {
188
+ this.element.id = this.getUniqueID(this.getModuleName());
189
+ }
190
+ if (this.enablePersistence) {
191
+ this.mergePersistData();
192
+ this.attachUnloadEvent();
193
+ }
194
+ const inst: Object[] = getValue('ej2_instances', this.element);
195
+ if (!inst || inst.indexOf(this) === -1) {
196
+ super.addInstance();
197
+ }
198
+ this.preRender();
199
+ this.injectModules();
200
+ // Throw a warning for the required modules to be injected.
201
+ const ignoredComponents: { [key: string]: string | string[] } = { // Add component to ignore it from injectable module validation
202
+ schedule: 'all',
203
+ diagram: 'all',
204
+ PdfViewer: 'all',
205
+ grid: ['logger'],
206
+ richtexteditor: ['link', 'table', 'image', 'audio', 'video', 'formatPainter', 'emojiPicker', 'pasteCleanup', 'htmlEditor', 'toolbar'],
207
+ treegrid: ['filter'],
208
+ gantt: ['tooltip'],
209
+ chart: ['Export', 'Zoom'],
210
+ accumulationchart: ['Export']
211
+ };
212
+ const component: string = this.getModuleName();
213
+ if (this.requiredModules && (!ignoredComponents[`${component}`] || ignoredComponents[`${component}`] !== 'all')) {
214
+ const modulesRequired: ModuleDeclaration[] = this.requiredModules();
215
+ for (const module of this.moduleLoader.getNonInjectedModules(modulesRequired)) {
216
+ const moduleName: string = module.name ? module.name : module.member;
217
+ if (ignoredComponents[`${component}`] && ignoredComponents[`${component}`].indexOf(module.member) !== -1) { continue; }
218
+ const componentName: string = component.charAt(0).toUpperCase() + component.slice(1); // To capitalize the component name
219
+ console.warn(`[WARNING] :: Module "${moduleName}" is not available in ${componentName} component! You either misspelled the module name or forgot to load it.`);
220
+ }
221
+ }
222
+ // Checked weather cases are valid or not. If control leads to more than five counts
223
+ this.render();
224
+ if (!this.mount) {
225
+ this.trigger('created');
226
+ } else {
227
+ this.accessMount();
228
+ }
229
+ }
230
+ }
231
+
232
+ /**
233
+ * It is used to process the post rendering functionalities to a component.
234
+ *
235
+ * @param {Node} wrapperElement ?
236
+ * @returns {void} ?
237
+ */
238
+ protected renderComplete(wrapperElement?: Node): void {
239
+ if (isBlazor()) {
240
+ const sfBlazor: string = 'sfBlazor';
241
+ // eslint-disable-next-line
242
+ (window as any)[sfBlazor].renderComplete(this.element, wrapperElement);
243
+ }
244
+ this.isRendered = true;
245
+ }
246
+
247
+ /**
248
+ * When invoked, applies the pending property changes immediately to the component.
249
+ *
250
+ * @returns {void} ?
251
+ */
252
+ public dataBind(): void {
253
+ this.injectModules();
254
+ super.dataBind();
255
+ }
256
+ /**
257
+ * Attach one or more event handler to the current component context.
258
+ * It is used for internal handling event internally within the component only.
259
+ *
260
+ * @param {BoundOptions[]| string} event - It is optional type either to Set the collection of event list or the eventName.
261
+ * @param {Function} handler - optional parameter Specifies the handler to run when the event occurs
262
+ * @param {Object} context - optional parameter Specifies the context to be bind in the handler.
263
+ * @returns {void} ?
264
+ * @private
265
+ */
266
+ public on(event: BoundOptions[] | string, handler?: Function, context?: Object): void {
267
+ if (typeof event === 'string') {
268
+ this.localObserver.on(event, handler, context);
269
+ } else {
270
+ for (const arg of event) {
271
+ this.localObserver.on(arg.event, arg.handler, arg.context);
272
+ }
273
+ }
274
+
275
+ }
276
+
277
+ /**
278
+ * To remove one or more event handler that has been attached with the on() method.
279
+ *
280
+ * @param {BoundOptions[]| string} event - It is optional type either to Set the collection of event list or the eventName.
281
+ * @param {Function} handler - optional parameter Specifies the function to run when the event occurs
282
+ * @returns {void} ?
283
+ * @private
284
+ */
285
+ public off(event: BoundOptions[] | string, handler?: Function): void {
286
+ if (typeof event === 'string') {
287
+ this.localObserver.off(event, handler);
288
+ } else {
289
+ for (const arg of event) {
290
+ this.localObserver.off(arg.event, arg.handler);
291
+ }
292
+ }
293
+ }
294
+ /**
295
+ * To notify the handlers in the specified event.
296
+ *
297
+ * @param {string} property - Specifies the event to be notify.
298
+ * @param {Object} argument - Additional parameters to pass while calling the handler.
299
+ * @returns {void} ?
300
+ * @private
301
+ */
302
+ public notify(property: string, argument: Object): void {
303
+ if (this.isDestroyed !== true) {
304
+ this.localObserver.notify(property, argument);
305
+ }
306
+ }
307
+ /**
308
+ * Get injected modules
309
+ *
310
+ * @returns {Function} ?
311
+ * @private
312
+ */
313
+ public getInjectedModules(): Function[] {
314
+ return this.injectedModules;
315
+ }
316
+
317
+ /**
318
+ * Dynamically injects the required modules to the component.
319
+ *
320
+ * @param {Function} moduleList ?
321
+ * @returns {void} ?
322
+ */
323
+ public static Inject(...moduleList: Function[]): void {
324
+ if (!this.prototype.injectedModules) {
325
+ this.prototype.injectedModules = [];
326
+ }
327
+ for (let i: number = 0; i < moduleList.length; i++) {
328
+ if (this.prototype.injectedModules.indexOf(moduleList[parseInt(i.toString(), 10)]) === -1) {
329
+ this.prototype.injectedModules.push(moduleList[parseInt(i.toString(), 10)]);
330
+ }
331
+ }
332
+ }
333
+
334
+ /**
335
+ * Initialize the constructor for component base
336
+ *
337
+ * @param {Object} options ?
338
+ * @param {string} selector ?
339
+ */
340
+ constructor(options?: Object, selector?: string | ElementType) {
341
+ super(options, selector);
342
+ if (isNullOrUndefined(this.enableRtl)) {
343
+ this.setProperties({ 'enableRtl': rightToLeft }, true);
344
+ }
345
+ if (isNullOrUndefined(this.locale)) {
346
+ this.setProperties({ 'locale': defaultCulture }, true);
347
+ }
348
+ this.moduleLoader = new ModuleLoader(this);
349
+ this.localObserver = new Observer(this);
350
+ // tslint:disable-next-line:no-function-constructor-with-string-args
351
+ onIntlChange.on('notifyExternalChange', this.detectFunction, this, this.randomId);
352
+ // Based on the considered control list we have count the instance
353
+ if (!isUndefined(selector)) {
354
+ this.appendTo();
355
+ }
356
+ }
357
+ /**
358
+ * This is a instance method to create an element.
359
+ *
360
+ * @param {string} tagName ?
361
+ * @param {ElementProperties} prop ?
362
+ * @param {boolean} isVDOM ?
363
+ * @returns {any} ?
364
+ * @private
365
+ */
366
+ // eslint-disable-next-line
367
+ public createElement(tagName: string, prop?: ElementProperties, isVDOM?: boolean): any {
368
+ return createElement(tagName, prop);
369
+ }
370
+ /**
371
+ *
372
+ * @param {Function} handler - handler to be triggered after state Updated.
373
+ * @param {any} argument - Arguments to be passed to caller.
374
+ * @returns {void} .
375
+ * @private
376
+ */
377
+ // eslint-disable-next-line
378
+ public triggerStateChange(handler?: Function, argument?: any): void {
379
+ if (this.isReactHybrid) {
380
+ // eslint-disable-next-line
381
+ (this as any).setState();
382
+ this.currentContext = { calls: handler, args: argument };
383
+ }
384
+
385
+ }
386
+ // tslint: enable: no-any
387
+ private injectModules(): void {
388
+ if (this.injectedModules && this.injectedModules.length) {
389
+ this.moduleLoader.inject(this.requiredModules(), this.injectedModules);
390
+ }
391
+ }
392
+
393
+ private detectFunction(args: Object): void {
394
+ const prop: string[] = Object.keys(args);
395
+ if (prop.length) {
396
+ this[prop[0]] = args[prop[0]];
397
+ }
398
+ }
399
+
400
+ private mergePersistData(): void {
401
+ let data: string;
402
+ if (versionBasedStatePersistence) {
403
+ data = window.localStorage.getItem(this.getModuleName() + this.element.id + this.ej2StatePersistenceVersion);
404
+ } else {
405
+ data = window.localStorage.getItem(this.getModuleName() + this.element.id);
406
+ }
407
+ if (!(isNullOrUndefined(data) || (data === ''))) {
408
+ this.setProperties(JSON.parse(data), true);
409
+ }
410
+ }
411
+ private setPersistData(): void {
412
+ if (!this.isDestroyed) {
413
+ if (versionBasedStatePersistence) {
414
+ window.localStorage.setItem(this.getModuleName() +
415
+ this.element.id + this.ej2StatePersistenceVersion, this.getPersistData());
416
+ } else {
417
+ window.localStorage.setItem(this.getModuleName() + this.element.id, this.getPersistData());
418
+ }
419
+ }
420
+ }
421
+
422
+ // eslint-disable-next-line
423
+ protected renderReactTemplates(callback?: any): void {
424
+ if (!isNullOrUndefined(callback)) {
425
+ callback();
426
+ }
427
+ }
428
+
429
+ // eslint-disable-next-line
430
+ protected clearTemplate(templateName?: string[], index?: any): void {
431
+ //No Code
432
+ }
433
+
434
+ private getUniqueID(definedName?: string): string {
435
+ if (this.isHistoryChanged()) {
436
+ componentCount = 0;
437
+ }
438
+ lastPageID = this.pageID(location.href);
439
+ lastHistoryLen = history.length;
440
+ return definedName + '_' + lastPageID + '_' + componentCount++;
441
+ }
442
+
443
+ private pageID(url: string): number {
444
+ let hash: number = 0;
445
+ if (url.length === 0) { return hash; }
446
+ for (let i: number = 0; i < url.length; i++) {
447
+ const char: number = url.charCodeAt(i);
448
+ hash = ((hash << 5) - hash) + char;
449
+ hash = hash & hash; // Convert to 32bit integer
450
+ }
451
+ return Math.abs(hash);
452
+ }
453
+
454
+ private isHistoryChanged(): boolean {
455
+ return lastPageID !== this.pageID(location.href) || lastHistoryLen !== history.length;
456
+ }
457
+
458
+ protected addOnPersist(options: string[]): string {
459
+ const persistObj: Object = {};
460
+ for (const key of options) {
461
+ let objValue: Object;
462
+ // eslint-disable-next-line
463
+ objValue = getValue(key, this);
464
+ if (!isUndefined(objValue)) {
465
+ setValue(key, this.getActualProperties(objValue), persistObj);
466
+ }
467
+ }
468
+ return JSON.stringify(persistObj, (key: string, value: Object) => {
469
+ return this.getActualProperties(value);
470
+ });
471
+ }
472
+
473
+ protected getActualProperties<T>(obj: T): T {
474
+ if (obj instanceof ChildProperty) {
475
+ return <T>getValue('properties', obj);
476
+ } else {
477
+ return obj;
478
+ }
479
+ }
480
+
481
+ protected ignoreOnPersist(options: string[]): string {
482
+ return JSON.stringify(this.iterateJsonProperties(this.properties, options));
483
+ }
484
+
485
+ protected iterateJsonProperties(obj: { [key: string]: Object }, ignoreList: string[]): Object {
486
+ const newObj: { [key: string]: Object } = {};
487
+ for (const key of Object.keys(obj)) {
488
+ if (ignoreList.indexOf(key) === -1) {
489
+ // eslint-disable-next-line
490
+ const value: any = obj[key];
491
+ if (typeof value === 'object' && !(value instanceof Array)) {
492
+ const newList: string[] = ignoreList.filter((str: string): boolean => {
493
+ const regExp: RegExpConstructor = RegExp;
494
+ return new regExp(key + '.').test(str);
495
+ }).map((str: string): string => {
496
+ return str.replace(key + '.', '');
497
+ });
498
+ newObj[`${key}`] = this.iterateJsonProperties(this.getActualProperties(value), newList);
499
+ } else {
500
+ newObj[`${key}`] = value;
501
+ }
502
+ }
503
+ }
504
+ return newObj;
505
+ }
506
+ }
507
+
508
+ //Function handling for page navigation detection
509
+ /* istanbul ignore next */
510
+ (() => {
511
+ if (typeof window !== 'undefined') {
512
+ window.addEventListener(
513
+ 'popstate',
514
+ /* istanbul ignore next */
515
+ () => {
516
+ componentCount = 0;
517
+ });
518
+ }
519
+ })();