@syncfusion/ej2-splitbuttons 20.1.47 → 20.2.36

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 (109) hide show
  1. package/dist/ej2-splitbuttons.umd.min.js +2 -2
  2. package/dist/ej2-splitbuttons.umd.min.js.map +1 -1
  3. package/dist/es6/ej2-splitbuttons.es2015.js +11 -3
  4. package/dist/es6/ej2-splitbuttons.es2015.js.map +1 -1
  5. package/dist/es6/ej2-splitbuttons.es5.js +11 -3
  6. package/dist/es6/ej2-splitbuttons.es5.js.map +1 -1
  7. package/dist/global/ej2-splitbuttons.min.js +2 -2
  8. package/dist/global/ej2-splitbuttons.min.js.map +1 -1
  9. package/dist/global/index.d.ts +1 -1
  10. package/dist/ts/button-group/button-group.ts +84 -0
  11. package/dist/ts/common/common.ts +203 -0
  12. package/dist/ts/drop-down-button/drop-down-button.ts +806 -0
  13. package/dist/ts/progress-button/progress-button.ts +689 -0
  14. package/dist/ts/split-button/split-button.ts +501 -0
  15. package/helpers/e2e/dropdownbuttonHelper.js +55 -38
  16. package/helpers/e2e/index.js +10 -8
  17. package/helpers/e2e/progressbuttonHelper.js +52 -35
  18. package/helpers/e2e/splitbuttonHelper.js +58 -41
  19. package/package.json +7 -7
  20. package/src/drop-down-button/drop-down-button.js +11 -3
  21. package/styles/bootstrap-dark.css +4 -338
  22. package/styles/bootstrap.css +4 -333
  23. package/styles/bootstrap4.css +12 -342
  24. package/styles/bootstrap5-dark.css +20 -331
  25. package/styles/bootstrap5.css +18 -329
  26. package/styles/button-group/_fusionnew-definition.scss +31 -0
  27. package/styles/button-group/_layout.scss +1 -1
  28. package/styles/button-group/_material3-definition.scss +31 -0
  29. package/styles/button-group/_theme.scss +48 -12
  30. package/styles/button-group/bootstrap-dark.css +1 -114
  31. package/styles/button-group/bootstrap.css +1 -108
  32. package/styles/button-group/bootstrap4.css +5 -119
  33. package/styles/button-group/bootstrap5-dark.css +15 -108
  34. package/styles/button-group/bootstrap5.css +13 -106
  35. package/styles/button-group/fabric-dark.css +1 -114
  36. package/styles/button-group/fabric.css +1 -114
  37. package/styles/button-group/fluent-dark.css +1 -114
  38. package/styles/button-group/fluent.css +1 -114
  39. package/styles/button-group/highcontrast-light.css +1 -114
  40. package/styles/button-group/highcontrast.css +1 -126
  41. package/styles/button-group/material-dark.css +1 -114
  42. package/styles/button-group/material.css +1 -115
  43. package/styles/button-group/tailwind-dark.css +9 -114
  44. package/styles/button-group/tailwind.css +9 -114
  45. package/styles/drop-down-button/_fusionnew-definition.scss +51 -0
  46. package/styles/drop-down-button/_layout.scss +4 -2
  47. package/styles/drop-down-button/_material3-definition.scss +51 -0
  48. package/styles/drop-down-button/bootstrap-dark.css +2 -36
  49. package/styles/drop-down-button/bootstrap.css +2 -36
  50. package/styles/drop-down-button/bootstrap4.css +3 -36
  51. package/styles/drop-down-button/bootstrap5-dark.css +4 -35
  52. package/styles/drop-down-button/bootstrap5.css +4 -35
  53. package/styles/drop-down-button/fabric-dark.css +2 -36
  54. package/styles/drop-down-button/fabric.css +2 -36
  55. package/styles/drop-down-button/fluent-dark.css +2 -36
  56. package/styles/drop-down-button/fluent.css +2 -36
  57. package/styles/drop-down-button/highcontrast-light.css +2 -36
  58. package/styles/drop-down-button/highcontrast.css +2 -36
  59. package/styles/drop-down-button/icons/_fusionnew.scss +10 -0
  60. package/styles/drop-down-button/icons/_material3.scss +10 -0
  61. package/styles/drop-down-button/material-dark.css +2 -36
  62. package/styles/drop-down-button/material.css +2 -36
  63. package/styles/drop-down-button/tailwind-dark.css +4 -36
  64. package/styles/drop-down-button/tailwind.css +4 -36
  65. package/styles/fabric-dark.css +4 -338
  66. package/styles/fabric.css +4 -338
  67. package/styles/fluent-dark.css +5 -339
  68. package/styles/fluent.css +5 -339
  69. package/styles/highcontrast-light.css +4 -338
  70. package/styles/highcontrast.css +4 -350
  71. package/styles/material-dark.css +4 -338
  72. package/styles/material.css +4 -339
  73. package/styles/progress-button/_fluent-definition.scss +1 -1
  74. package/styles/progress-button/_fusionnew-definition.scss +21 -0
  75. package/styles/progress-button/_material3-definition.scss +21 -0
  76. package/styles/progress-button/bootstrap-dark.css +3 -120
  77. package/styles/progress-button/bootstrap.css +3 -120
  78. package/styles/progress-button/bootstrap4.css +3 -120
  79. package/styles/progress-button/bootstrap5-dark.css +3 -124
  80. package/styles/progress-button/bootstrap5.css +3 -124
  81. package/styles/progress-button/fabric-dark.css +3 -120
  82. package/styles/progress-button/fabric.css +3 -120
  83. package/styles/progress-button/fluent-dark.css +4 -125
  84. package/styles/progress-button/fluent.css +4 -125
  85. package/styles/progress-button/highcontrast-light.css +3 -120
  86. package/styles/progress-button/highcontrast.css +3 -120
  87. package/styles/progress-button/material-dark.css +3 -120
  88. package/styles/progress-button/material.css +3 -120
  89. package/styles/progress-button/tailwind-dark.css +3 -124
  90. package/styles/progress-button/tailwind.css +3 -124
  91. package/styles/split-button/_fusionnew-definition.scss +25 -0
  92. package/styles/split-button/_material3-definition.scss +25 -0
  93. package/styles/split-button/bootstrap-dark.css +1 -71
  94. package/styles/split-button/bootstrap.css +1 -71
  95. package/styles/split-button/bootstrap4.css +4 -70
  96. package/styles/split-button/bootstrap5-dark.css +1 -67
  97. package/styles/split-button/bootstrap5.css +1 -67
  98. package/styles/split-button/fabric-dark.css +1 -71
  99. package/styles/split-button/fabric.css +1 -71
  100. package/styles/split-button/fluent-dark.css +1 -67
  101. package/styles/split-button/fluent.css +1 -67
  102. package/styles/split-button/highcontrast-light.css +1 -71
  103. package/styles/split-button/highcontrast.css +1 -71
  104. package/styles/split-button/material-dark.css +1 -71
  105. package/styles/split-button/material.css +1 -71
  106. package/styles/split-button/tailwind-dark.css +1 -71
  107. package/styles/split-button/tailwind.css +1 -71
  108. package/styles/tailwind-dark.css +14 -343
  109. package/styles/tailwind.css +14 -343
@@ -0,0 +1,689 @@
1
+ import { Button, IconPosition } from '@syncfusion/ej2-buttons';
2
+ import { EventHandler, Property, INotifyPropertyChanged, NotifyPropertyChanges, Animation, Effect, attributes } from '@syncfusion/ej2-base';
3
+ import { EmitType, Event, BaseEventArgs, remove, removeClass } from '@syncfusion/ej2-base';
4
+ import { Complex, ChildProperty, SanitizeHtmlHelper } from '@syncfusion/ej2-base';
5
+ import { createSpinner, showSpinner, hideSpinner } from '@syncfusion/ej2-popups';
6
+ import { ProgressButtonModel, SpinSettingsModel, AnimationSettingsModel } from './progress-button-model';
7
+
8
+ const HIDESPINNER: string = 'e-hide-spinner';
9
+ const PROGRESS: string = 'e-progress';
10
+ const PROGRESSACTIVE: string = 'e-progress-active';
11
+ const CONTENTCLS: string = 'e-btn-content';
12
+ /**
13
+ * Defines the spin settings.
14
+ */
15
+ export class SpinSettings extends ChildProperty<SpinSettings> {
16
+ /**
17
+ * Specifies the template content to be displayed in a spinner.
18
+ *
19
+ * @default null
20
+ */
21
+ @Property(null)
22
+ public template: string;
23
+ /**
24
+ * Sets the width of a spinner.
25
+ *
26
+ * @default '16'
27
+ */
28
+ @Property(16)
29
+ public width: string | number;
30
+ /**
31
+ * Specifies the position of a spinner in the progress button. The possible values are:
32
+ * * Left: The spinner will be positioned to the left of the text content.
33
+ * * Right: The spinner will be positioned to the right of the text content.
34
+ * * Top: The spinner will be positioned at the top of the text content.
35
+ * * Bottom: The spinner will be positioned at the bottom of the text content.
36
+ * * Center: The spinner will be positioned at the center of the progress button.
37
+ *
38
+ * @default 'Left'
39
+ * @aspType Syncfusion.EJ2.SplitButtons.SpinPosition
40
+ * @blazorType Syncfusion.Blazor.SplitButtons.SpinPosition
41
+ * @isEnumeration true
42
+ */
43
+ @Property('Left')
44
+ public position: SpinPosition;
45
+ }
46
+ /**
47
+ * Defines the animation settings.
48
+ */
49
+ export class AnimationSettings extends ChildProperty<AnimationSettings> {
50
+ /**
51
+ * Specifies the duration taken to animate.
52
+ *
53
+ * @default 400
54
+ */
55
+ @Property(400)
56
+ public duration: number;
57
+ /**
58
+ * Specifies the effect of animation.
59
+ *
60
+ * @default 'None'
61
+ * @aspType Syncfusion.EJ2.SplitButtons.AnimationEffect
62
+ * @blazorType Syncfusion.Blazor.SplitButtons.AnimationEffect
63
+ * @isEnumeration true
64
+ */
65
+ @Property('None')
66
+ public effect: AnimationEffect;
67
+ /**
68
+ * Specifies the animation timing function.
69
+ *
70
+ * @default 'ease'
71
+ */
72
+ @Property('ease')
73
+ public easing: string;
74
+ }
75
+
76
+ /**
77
+ * The ProgressButton visualizes the progression of an operation to indicate the user
78
+ * that a process is happening in the background with visual representation.
79
+ * ```html
80
+ * <button id="element"></button>
81
+ * ```
82
+ * ```typescript
83
+ * <script>
84
+ * var progressButtonObj = new ProgressButton({ content: 'Progress Button' });
85
+ * progressButtonObj.appendTo("#element");
86
+ * </script>
87
+ * ```
88
+ */
89
+ @NotifyPropertyChanges
90
+ export class ProgressButton extends Button implements INotifyPropertyChanged {
91
+ private progressTime: number;
92
+ private percent: number;
93
+ private isPaused: boolean;
94
+ private timerId: number;
95
+ private step: number = 1;
96
+ private interval: number;
97
+ private eIsVertical: boolean;
98
+
99
+ /**
100
+ * Enables or disables the background filler UI in the progress button.
101
+ *
102
+ * @default false
103
+ */
104
+ @Property(false)
105
+ public enableProgress: boolean;
106
+
107
+ /**
108
+ * Specifies the duration of progression in the progress button.
109
+ *
110
+ * @default 2000
111
+ */
112
+ @Property(2000)
113
+ public duration: number;
114
+
115
+ /**
116
+ * Positions an icon in the progress button. The possible values are:
117
+ * * Left: The icon will be positioned to the left of the text content.
118
+ * * Right: The icon will be positioned to the right of the text content.
119
+ * * Top: The icon will be positioned at the top of the text content.
120
+ * * Bottom: The icon will be positioned at the bottom of the text content.
121
+ *
122
+ * @default "Left"
123
+ */
124
+ @Property('Left')
125
+ public iconPosition: IconPosition;
126
+
127
+ /**
128
+ * Defines class/multiple classes separated by a space for the progress button that is used to include an icon.
129
+ * Progress button can also include font icon and sprite image.
130
+ *
131
+ * @default ""
132
+ */
133
+ @Property('')
134
+ public iconCss: string;
135
+
136
+ /**
137
+ * Enables or disables the progress button.
138
+ *
139
+ * @default false.
140
+ */
141
+ @Property(false)
142
+ public disabled: boolean;
143
+
144
+ /**
145
+ * Allows the appearance of the progress button to be enhanced and visually appealing when set to `true`.
146
+ *
147
+ * @default false
148
+ */
149
+ @Property(false)
150
+ public isPrimary: boolean;
151
+
152
+ /**
153
+ * Specifies the root CSS class of the progress button that allows customization of component’s appearance.
154
+ * The progress button types, styles, and size can be achieved by using this property.
155
+ *
156
+ * @default ""
157
+ */
158
+ @Property('')
159
+ public cssClass: string;
160
+
161
+ /**
162
+ * Defines the text `content` of the progress button element.
163
+ *
164
+ * @default ""
165
+ */
166
+ @Property('')
167
+ public content: string;
168
+
169
+ /**
170
+ * Makes the progress button toggle, when set to `true`. When you click it, the state changes from normal to active.
171
+ *
172
+ * @default false
173
+ */
174
+ @Property(false)
175
+ public isToggle: boolean;
176
+
177
+ /**
178
+ * Defines whether to allow the cross-scripting site or not.
179
+ *
180
+ * @default false
181
+ */
182
+ @Property(false)
183
+ public enableHtmlSanitizer: boolean;
184
+
185
+ /**
186
+ * Specifies a spinner and its related properties.
187
+ */
188
+ @Complex<SpinSettingsModel>({}, SpinSettings)
189
+ public spinSettings: SpinSettingsModel;
190
+
191
+ /**
192
+ * Specifies the animation settings.
193
+ */
194
+ @Complex<AnimationSettingsModel>({}, AnimationSettings)
195
+ public animationSettings: AnimationSettingsModel;
196
+
197
+ /**
198
+ * Triggers once the component rendering is completed.
199
+ *
200
+ * @event created
201
+ * @blazorProperty 'Created'
202
+ */
203
+ @Event()
204
+ public created: EmitType<Event>;
205
+
206
+ /**
207
+ * Triggers when the progress starts.
208
+ *
209
+ * @event begin
210
+ * @blazorProperty 'OnBegin'
211
+ */
212
+ @Event()
213
+ public begin: EmitType<ProgressEventArgs>;
214
+
215
+ /**
216
+ * Triggers in specified intervals.
217
+ *
218
+ * @event progress
219
+ * @blazorProperty 'Progressing'
220
+ */
221
+ @Event()
222
+ public progress: EmitType<ProgressEventArgs>;
223
+
224
+ /**
225
+ * Triggers when the progress is completed.
226
+ *
227
+ * @event end
228
+ * @blazorProperty 'OnEnd'
229
+ */
230
+ @Event()
231
+ public end: EmitType<ProgressEventArgs>;
232
+
233
+ /**
234
+ * Triggers when the progress is incomplete.
235
+ *
236
+ * @event fail
237
+ * @blazorProperty 'OnFailure'
238
+ */
239
+ @Event()
240
+ public fail: EmitType<Event>;
241
+
242
+ /**
243
+ * Constructor for creating the widget.
244
+ *
245
+ * @param {ProgressButtonModel} options - Specifies progress button model
246
+ * @param {string|HTMLButtonElement} element - Specifies element
247
+ */
248
+ constructor(options?: ProgressButtonModel, element?: string | HTMLButtonElement) {
249
+ super(options, element);
250
+ }
251
+
252
+ protected preRender(): void {
253
+ super.preRender();
254
+ }
255
+
256
+ /**
257
+ * Initialize the Component rendering
258
+ *
259
+ * @returns {void}
260
+ * @private
261
+ */
262
+ public render(): void {
263
+ super.render();
264
+ this.init();
265
+ this.wireEvents();
266
+ this.setAria();
267
+ this.renderComplete();
268
+ }
269
+
270
+ /**
271
+ * Starts the button progress at the specified percent.
272
+ *
273
+ * @param {number} percent - Starts the button progress at this percent.
274
+ * @returns {void}
275
+ */
276
+ public start(percent?: number): void {
277
+ this.isPaused = false;
278
+ this.startProgress(percent ? percent : this.percent, this.progressTime);
279
+ }
280
+
281
+ /**
282
+ * Stops the button progress.
283
+ *
284
+ * @returns {void}
285
+ */
286
+ public stop(): void {
287
+ this.isPaused = true;
288
+ cancelAnimationFrame(this.timerId);
289
+ }
290
+
291
+ /**
292
+ * Complete the button progress.
293
+ *
294
+ * @returns {void}
295
+ */
296
+ public progressComplete(): void {
297
+ this.isPaused = false;
298
+ this.finishProgress();
299
+ }
300
+
301
+ /**
302
+ * Get component name.
303
+ *
304
+ * @returns {string} - Module Name
305
+ * @private
306
+ */
307
+ public getModuleName(): string {
308
+ return 'progress-btn';
309
+ }
310
+
311
+ /**
312
+ * Destroys the widget.
313
+ *
314
+ * @returns {void}
315
+ */
316
+ public destroy(): void {
317
+ let classList: string[] = [HIDESPINNER, PROGRESSACTIVE, 'e-round-corner', 'e-' + super.getModuleName(),
318
+ 'e-spin-' + this.spinSettings.position.toLowerCase()];
319
+ super.destroy();
320
+ this.unWireEvents();
321
+ this.element.innerHTML = '';
322
+ if (this.cssClass) {
323
+ classList = classList.concat(this.cssClass.split(' '));
324
+ }
325
+ removeClass([this.element], classList);
326
+ const css: string[] = this.element.getAttribute('class') ? ['aria-label', 'aria-valuemin', 'aria-valuemax', 'aria-valuenow']
327
+ : ['aria-label', 'aria-valuemin', 'aria-valuemax', 'aria-valuenow', 'class'];
328
+ css.forEach((key: string) => {
329
+ this.element.removeAttribute(key);
330
+ });
331
+ if (this.disabled) {
332
+ this.element.removeAttribute('disabled');
333
+ }
334
+ }
335
+
336
+ private init(): void {
337
+ this.element.classList.add('e-' + super.getModuleName());
338
+ this.setContent();
339
+ this.createSpinner();
340
+ if (this.enableProgress) {
341
+ this.createProgress();
342
+ }
343
+ }
344
+
345
+ private createSpinner(): void {
346
+ const spinner: HTMLElement = this.createElement('span', { className: 'e-spinner' });
347
+ this.setSpinPosition(spinner);
348
+ createSpinner(
349
+ {
350
+ target: spinner, width: this.spinSettings.width || 16, template: this.spinSettings.template
351
+ },
352
+ this.createElement);
353
+ }
354
+
355
+ private getSpinner(): HTMLElement {
356
+ return this.element.getElementsByClassName('e-spinner')[0] as HTMLElement;
357
+ }
358
+
359
+ private getProgress(): HTMLElement {
360
+ return this.element.getElementsByClassName(PROGRESS)[0] as HTMLElement;
361
+ }
362
+
363
+ private setSpinPosition(ele: HTMLElement): void {
364
+ const position: SpinPosition = this.spinSettings.position || 'Left';
365
+ if (position === 'Left' || position === 'Top') {
366
+ this.element.insertBefore(ele, this.element.getElementsByClassName(CONTENTCLS)[0]);
367
+ } else {
368
+ this.element.appendChild(ele);
369
+ }
370
+ this.element.classList.add('e-spin-' + position.toLowerCase());
371
+ }
372
+
373
+ private createProgress(): void {
374
+ this.element.appendChild(this.createElement('span', { className: PROGRESS }));
375
+ }
376
+
377
+ private setContent(): void {
378
+ let cont: string;
379
+ cont = this.element.innerHTML;
380
+ if (this.enableHtmlSanitizer) {
381
+ cont = SanitizeHtmlHelper.sanitize(this.element.innerHTML);
382
+ }
383
+ this.element.innerHTML = '';
384
+ this.element.appendChild(this.createElement('span', { className: CONTENTCLS, innerHTML: cont }));
385
+ }
386
+
387
+ private setContentIcon(content: string): void {
388
+ const contElem: HTMLElement = this.createElement('span', { className: CONTENTCLS, innerHTML: content });
389
+ if (this.iconCss) {
390
+ const span: HTMLElement = this.createElement('span', { className: 'e-btn-icon ' + this.iconCss });
391
+ if (!this.element.textContent.trim()) {
392
+ this.element.classList.add('e-icon-btn');
393
+ } else {
394
+ span.classList.add('e-icon-' + this.iconPosition.toLowerCase());
395
+ if (this.iconPosition === 'Top' || this.iconPosition === 'Bottom') {
396
+ this.element.classList.add('e-' + this.iconPosition.toLowerCase() + '-icon-btn');
397
+ }
398
+ }
399
+ const node: Node = contElem.childNodes[0];
400
+ if (node && (this.iconPosition === 'Left' || this.iconPosition === 'Top')) {
401
+ contElem.insertBefore(span, node);
402
+ } else {
403
+ contElem.appendChild(span);
404
+ }
405
+ }
406
+ this.element.appendChild(contElem);
407
+ }
408
+
409
+ private clickHandler(): void {
410
+ if (this.element.classList.contains(PROGRESSACTIVE)) {
411
+ return;
412
+ }
413
+ this.startProgress();
414
+ }
415
+
416
+ private startProgress(percent?: number, progressTime?: number): void {
417
+ const clsList: DOMTokenList = this.element.classList;
418
+ const isVertical: boolean = clsList.contains('e-vertical');
419
+ clsList.add(PROGRESSACTIVE);
420
+ if (!(clsList.contains(HIDESPINNER))) {
421
+ showSpinner(this.element);
422
+ }
423
+ this.startAnimate(
424
+ Date.now(), progressTime ? progressTime : 0, progressTime ? Date.now() - (this.duration * 1 / 100) : Date.now(),
425
+ percent ? percent : 0, 0, this.step, 0, isVertical);
426
+ this.startContAnimate();
427
+ }
428
+
429
+ private startAnimate(
430
+ timestamp: number, progressTime: number, prevTime: number, percent: number, prevPercent: number,
431
+ step: number, prevProgressTime: number, isVertical: boolean): void {
432
+ try {
433
+ const timeDiff: number = timestamp - prevTime;
434
+ const stepTime: number = this.duration * step / 100;
435
+ const timeDiffBuffer: number = timeDiff ? (timeDiff < stepTime ? timeDiff - stepTime : timeDiff % stepTime) : 0;
436
+ this.progressTime = progressTime = progressTime + timeDiff - timeDiffBuffer;
437
+ prevTime = timestamp - timeDiffBuffer;
438
+ percent = percent + (timeDiff - timeDiffBuffer) / this.duration * 100;
439
+ prevPercent = ((progressTime - prevProgressTime) % stepTime === 0 || percent === 100) ? percent : prevPercent;
440
+ const args: ProgressEventArgs = { percent: prevPercent, currentDuration: progressTime, step: step };
441
+ this.eIsVertical = isVertical;
442
+ if (percent === 0) {
443
+ this.trigger('begin', args, (observedArgs: ProgressEventArgs) => {
444
+ this.successCallback(observedArgs, percent, prevPercent, progressTime, prevProgressTime, timeDiffBuffer, prevTime);
445
+ });
446
+ } else if (percent === 100 || progressTime === this.duration) {
447
+ this.trigger('end', args, (observedArgs: ProgressEventArgs) => {
448
+ this.successCallback(observedArgs, percent, prevPercent, progressTime, prevProgressTime, timeDiffBuffer, prevTime);
449
+ });
450
+ } else {
451
+ this.trigger('progress', args, (observedArgs: ProgressEventArgs) => {
452
+ this.successCallback(observedArgs, percent, prevPercent, progressTime, prevProgressTime, timeDiffBuffer, prevTime);
453
+ });
454
+ }
455
+ } catch (e) {
456
+ cancelAnimationFrame(this.timerId);
457
+ this.trigger('fail', e);
458
+ }
459
+ }
460
+
461
+ private successCallback(
462
+ args: ProgressEventArgs, perc: number, pPerc: number, prgTim: number, pPrgTim: number, timDif: number, pTim: number): void {
463
+ let percent: number = perc; let prevPercent: number = pPerc; const timeDiffBuffer: number = timDif;
464
+ const progressTime: number = prgTim; let prevProgressTime: number = pPrgTim;
465
+ const prevTime: number = pTim; const isVertical: boolean = this.eIsVertical;
466
+ if (percent !== args.percent && args.percent !== prevPercent) {
467
+ percent = args.percent;
468
+ }
469
+ this.percent = percent;
470
+ this.step = args.step;
471
+ if ((progressTime - prevProgressTime) % (this.duration * args.step / 100) === 0 || percent === 100) {
472
+ this.timerId = requestAnimationFrame(() => {
473
+ if (this.enableProgress) {
474
+ this.getProgress().style[isVertical ? 'height' : 'width'] = percent + '%';
475
+ }
476
+ this.element.setAttribute('aria-valuenow', percent.toString());
477
+ });
478
+ prevPercent = percent;
479
+ prevProgressTime = progressTime;
480
+ }
481
+ if (!this.isPaused) {
482
+ if (progressTime < this.duration && percent < 100) {
483
+ this.interval = window.setTimeout(() => {
484
+ this.startAnimate(
485
+ Date.now(), progressTime, prevTime, percent,
486
+ prevPercent, args.step, prevProgressTime, isVertical);
487
+ }, (this.duration / 100) - timeDiffBuffer);
488
+ } else {
489
+ this.interval = window.setTimeout(() => {
490
+ this.progressTime = this.percent = 0;
491
+ if (this.enableProgress) {
492
+ this.getProgress().style[isVertical ? 'height' : 'width'] = '0%';
493
+ }
494
+ this.element.setAttribute('aria-valuenow', '0');
495
+ this.hideSpin();
496
+ }, 100);
497
+ }
498
+ }
499
+ }
500
+ private startContAnimate(): void {
501
+ const ele: HTMLElement = this.element.getElementsByClassName(CONTENTCLS)[0] as HTMLElement;
502
+ if (this.animationSettings.effect !== 'None') {
503
+ (new Animation({})).animate(
504
+ ele,
505
+ {
506
+ duration: this.animationSettings.duration,
507
+ name: 'Progress' + this.animationSettings.effect as Effect,
508
+ timingFunction: this.animationSettings.easing,
509
+ begin: () => {
510
+ if (this.spinSettings.position === 'Center') {
511
+ this.setSpinnerSize();
512
+ }
513
+ },
514
+ end: () => {
515
+ ele.classList.add('e-animate-end');
516
+ }
517
+ });
518
+ } else if (this.spinSettings.position === 'Center') {
519
+ this.setSpinnerSize();
520
+ }
521
+ }
522
+
523
+ private finishProgress(): void {
524
+ const clsList: DOMTokenList = this.element.classList;
525
+ const isVertical: boolean = clsList.contains('e-vertical');
526
+ clsList.add(PROGRESSACTIVE);
527
+ const count: number = 100;
528
+ for (let i: number = this.percent; i < count; i++) {
529
+ i += 10;
530
+ if (i > 100) {
531
+ i = 100;
532
+ }
533
+ if (this.enableProgress) {
534
+ this.getProgress().style[isVertical ? 'height' : 'width'] = (this.percent < 100) ? (i + '%') : '100%';
535
+ }
536
+ }
537
+ this.element.setAttribute('aria-valuenow', '0');
538
+ this.hideSpin();
539
+ const args: ProgressEventArgs = {step: this.step, currentDuration: this.progressTime, percent: 100};
540
+ clearTimeout(this.interval);
541
+ this.trigger('end', args);
542
+ this.progressTime = this.percent = 0;
543
+ }
544
+
545
+ private setSpinnerSize(): void {
546
+ const ele: HTMLElement = this.element.getElementsByClassName(CONTENTCLS)[0] as HTMLElement;
547
+ const spinner: HTMLElement = this.getSpinner();
548
+ spinner.style.width = Math.max(spinner.offsetWidth, ele.offsetWidth) + 'px';
549
+ spinner.style.height = Math.max(spinner.offsetHeight, ele.offsetHeight) + 'px';
550
+ ele.classList.add('e-cont-animate');
551
+ }
552
+
553
+ private hideSpin(): void {
554
+ const cont: Element = this.element.getElementsByClassName(CONTENTCLS)[0];
555
+ if (!(this.element.classList.contains(HIDESPINNER))) {
556
+ hideSpinner(this.element);
557
+ }
558
+ this.element.classList.remove(PROGRESSACTIVE);
559
+ if (this.animationSettings.effect !== 'None') {
560
+ cont.classList.remove('e-animate-end');
561
+ }
562
+ if (this.spinSettings.position === 'Center') {
563
+ const ele: HTMLElement = this.getSpinner();
564
+ cont.classList.remove('e-cont-animate');
565
+ ele.style.width = 'auto';
566
+ ele.style.height = 'auto';
567
+ }
568
+ }
569
+
570
+ private setIconSpan(): void {
571
+ const cont: Element = this.element.getElementsByClassName(CONTENTCLS)[0];
572
+ const iconSpan: Element = this.element.getElementsByClassName('e-btn-icon')[0];
573
+ if (cont.childNodes[0] && (this.iconPosition === 'Left' || this.iconPosition === 'Top')) {
574
+ cont.insertBefore(iconSpan, cont.childNodes[0]);
575
+ } else {
576
+ cont.appendChild(iconSpan);
577
+ }
578
+ }
579
+
580
+ private setAria(): void {
581
+ attributes(this.element, {
582
+ 'aria-label': this.element.textContent + ' progress', 'aria-valuemin': '0', 'aria-valuemax': '100', 'aria-valuenow': '0'
583
+ });
584
+ }
585
+
586
+ protected wireEvents(): void {
587
+ EventHandler.add(this.element, 'click', this.clickHandler, this);
588
+ }
589
+
590
+ protected unWireEvents(): void {
591
+ EventHandler.remove(this.element, 'click', this.clickHandler);
592
+ }
593
+
594
+ /**
595
+ * Called internally if any of the property value changed.
596
+ *
597
+ * @param {ProgressButtonModel} newProp - Specifies new properties
598
+ * @param {ProgressButtonModel} oldProp - Specifies old properties
599
+ * @returns {void}
600
+ * @private
601
+ */
602
+ public onPropertyChanged(newProp: ProgressButtonModel, oldProp: ProgressButtonModel): void {
603
+ const ele: HTMLButtonElement = this.element; let isSpinning: boolean = false;
604
+ const clsList: DOMTokenList = this.element.querySelector('.e-spinner-pane').classList;
605
+ if (clsList.contains('e-spin-show')) {
606
+ isSpinning = true;
607
+ }
608
+ super.onPropertyChanged(newProp, oldProp);
609
+ for (const prop of Object.keys(newProp)) {
610
+ switch (prop) {
611
+ case 'content':
612
+ this.setContent();
613
+ this.createSpinner();
614
+ if (isSpinning) {
615
+ showSpinner(this.element);
616
+ isSpinning = false;
617
+ }
618
+ if (this.enableProgress) {
619
+ this.createProgress();
620
+ }
621
+ ele.setAttribute('aria-label', ele.textContent + ' progress');
622
+ break;
623
+ case 'iconCss':
624
+ if (!oldProp.iconCss) {
625
+ this.setIconSpan();
626
+ }
627
+ break;
628
+ case 'iconPosition':
629
+ this.setIconSpan();
630
+ break;
631
+ case 'enableProgress':
632
+ if (newProp.enableProgress) {
633
+ this.createProgress();
634
+ } else {
635
+ remove(this.getProgress());
636
+ }
637
+ break;
638
+ case 'spinSettings':
639
+ if (newProp.spinSettings.position) {
640
+ ele.classList.remove('e-spin-' + oldProp.spinSettings.position.toLowerCase());
641
+ this.setSpinPosition(this.getSpinner());
642
+ }
643
+ if (newProp.spinSettings.template || newProp.spinSettings.width) {
644
+ ele.removeChild(this.getSpinner());
645
+ this.createSpinner();
646
+ }
647
+ break;
648
+ }
649
+ }
650
+ }
651
+
652
+ /**
653
+ * Sets the focus to ProgressButton
654
+ * its native method
655
+ *
656
+ * @public
657
+ * @returns {void}
658
+ */
659
+ public focusIn(): void {
660
+ this.element.focus();
661
+ }
662
+ }
663
+ /**
664
+ * Defines the spin position of progress button.
665
+ */
666
+ export type SpinPosition = 'Left' | 'Right' | 'Top' | 'Bottom' | 'Center';
667
+ /**
668
+ * Defines the animation effect of progress button.
669
+ */
670
+ export type AnimationEffect = 'None' | 'SlideLeft' | 'SlideRight' | 'SlideUp' | 'SlideDown' | 'ZoomIn' | 'ZoomOut';
671
+ /**
672
+ * Interface for progress event arguments.
673
+ */
674
+ export interface ProgressEventArgs extends BaseEventArgs {
675
+ /**
676
+ * Indicates the current state of progress in percentage.
677
+ */
678
+ percent: number;
679
+ /**
680
+ * Indicates the current duration of the progress.
681
+ */
682
+ currentDuration: number;
683
+ /**
684
+ * Specifies the interval.
685
+ *
686
+ * @default 1
687
+ */
688
+ step: number;
689
+ }