ng-hub-ui-avatar 19.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,891 @@
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken, Injectable, Optional, Inject, EventEmitter, SecurityContext, Component, Input, Output, NgModule } from '@angular/core';
3
+ import { NgStyle, NgIf, CommonModule } from '@angular/common';
4
+ import { takeWhile, map } from 'rxjs/operators';
5
+ import * as i1 from '@angular/common/http';
6
+ import * as i3 from '@angular/platform-browser';
7
+
8
+ /**
9
+ * Contract of all async sources.
10
+ * Every async source must implement the processResponse method that extracts the avatar url from the data
11
+ */
12
+ class AsyncSource {
13
+ constructor(sourceId) {
14
+ this.sourceId = sourceId;
15
+ }
16
+ }
17
+
18
+ var AvatarSource;
19
+ (function (AvatarSource) {
20
+ AvatarSource["FACEBOOK"] = "facebook";
21
+ AvatarSource["GOOGLE"] = "google";
22
+ AvatarSource["TWITTER"] = "twitter";
23
+ AvatarSource["INSTAGRAM"] = "instagram";
24
+ AvatarSource["VKONTAKTE"] = "vkontakte";
25
+ AvatarSource["SKYPE"] = "skype";
26
+ AvatarSource["GRAVATAR"] = "gravatar";
27
+ AvatarSource["GITHUB"] = "github";
28
+ AvatarSource["CUSTOM"] = "custom";
29
+ AvatarSource["INITIALS"] = "initials";
30
+ AvatarSource["VALUE"] = "value";
31
+ })(AvatarSource || (AvatarSource = {}));
32
+
33
+ /**
34
+ * Facebook source implementation.
35
+ * Fetch avatar source based on facebook identifier
36
+ * and image size
37
+ */
38
+ class Facebook {
39
+ constructor(sourceId) {
40
+ this.sourceId = sourceId;
41
+ this.sourceType = AvatarSource.FACEBOOK;
42
+ }
43
+ getAvatar(size) {
44
+ return ('https://graph.facebook.com/' +
45
+ `${this.sourceId}/picture?width=${size}&height=${size}`);
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Twitter source implementation.
51
+ * Fetch avatar source based on google identifier
52
+ * and image size
53
+ */
54
+ class Twitter {
55
+ constructor(sourceId) {
56
+ this.sourceId = sourceId;
57
+ this.sourceType = AvatarSource.TWITTER;
58
+ }
59
+ getAvatar(size) {
60
+ const twitterImgSize = this.getImageSize(size);
61
+ return `https://twitter.com/${this.sourceId}/profile_image?size=${twitterImgSize}`;
62
+ }
63
+ getImageSize(size) {
64
+ if (size <= 24) {
65
+ return 'mini';
66
+ }
67
+ if (size <= 48) {
68
+ return 'normal';
69
+ }
70
+ if (size <= 73) {
71
+ return 'bigger';
72
+ }
73
+ return 'original';
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Google source implementation.
79
+ * Fetch avatar source based on google identifier
80
+ * and image size
81
+ */
82
+ class Google extends AsyncSource {
83
+ constructor(sourceId) {
84
+ super(sourceId);
85
+ this.sourceType = AvatarSource.GOOGLE;
86
+ }
87
+ getAvatar() {
88
+ return `https://picasaweb.google.com/data/entry/api/user/${this.sourceId}?alt=json`;
89
+ }
90
+ /**
91
+ * Extract google avatar from json data
92
+ */
93
+ processResponse(data, size) {
94
+ const avatarSrc = data.entry.gphoto$thumbnail.$t;
95
+ if (avatarSrc) {
96
+ return avatarSrc.replace('s64', 's' + size);
97
+ }
98
+ return null;
99
+ }
100
+ }
101
+
102
+ /**
103
+ * Instagram source implementation.
104
+ * Fetch avatar source based on instagram identifier
105
+ */
106
+ class Instagram extends AsyncSource {
107
+ constructor(sourceId) {
108
+ super(sourceId);
109
+ this.sourceType = AvatarSource.INSTAGRAM;
110
+ }
111
+ getAvatar() {
112
+ return `https://www.instagram.com/${this.sourceId}/?__a=1`;
113
+ }
114
+ /**
115
+ * extract instagram avatar from json data
116
+ */
117
+ processResponse(data, size) {
118
+ return `${data.graphql.user.profile_pic_url_hd}&s=${size}`;
119
+ }
120
+ }
121
+
122
+ /**
123
+ * Custom source implementation.
124
+ * return custom image as an avatar
125
+ *
126
+ */
127
+ class Custom {
128
+ constructor(sourceId) {
129
+ this.sourceId = sourceId;
130
+ this.sourceType = AvatarSource.CUSTOM;
131
+ }
132
+ getAvatar() {
133
+ return this.sourceId;
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Initials source implementation.
139
+ * return the initials of the given value
140
+ */
141
+ class Initials {
142
+ constructor(sourceId) {
143
+ this.sourceId = sourceId;
144
+ this.sourceType = AvatarSource.INITIALS;
145
+ }
146
+ getAvatar(size) {
147
+ return this.getInitials(this.sourceId, size);
148
+ }
149
+ /**
150
+ * Returns the initial letters of a name in a string.
151
+ */
152
+ getInitials(name, size) {
153
+ name = name.trim();
154
+ if (!name) {
155
+ return '';
156
+ }
157
+ const initials = name.split(' ');
158
+ if (size && size < initials.length) {
159
+ return this.constructInitials(initials.slice(0, size));
160
+ }
161
+ else {
162
+ return this.constructInitials(initials);
163
+ }
164
+ }
165
+ /**
166
+ * Iterates a person's name string to get the initials of each word in uppercase.
167
+ */
168
+ constructInitials(elements) {
169
+ if (!elements || !elements.length) {
170
+ return '';
171
+ }
172
+ return elements
173
+ .filter(element => element && element.length > 0)
174
+ .map(element => element[0].toUpperCase())
175
+ .join('');
176
+ }
177
+ }
178
+
179
+ function isRetina() {
180
+ if (typeof window !== 'undefined' && window !== null) {
181
+ if (window.devicePixelRatio > 1.25) {
182
+ return true;
183
+ }
184
+ const mediaQuery = '(-webkit-min-device-pixel-ratio: 1.25), (min--moz-device-pixel-ratio: 1.25), (-o-min-device-pixel-ratio: 5/4), (min-resolution: 1.25dppx)';
185
+ if (window.matchMedia && window.matchMedia(mediaQuery).matches) {
186
+ return true;
187
+ }
188
+ }
189
+ return false;
190
+ }
191
+ /**
192
+ * Helper function to calculate MD5 hash using the Crypto API.
193
+ */
194
+ function hashMD5(value) {
195
+ // Convert string to Uint8Array
196
+ const encoder = new TextEncoder();
197
+ const data = encoder.encode(value);
198
+ // Use SubtleCrypto for hashing
199
+ return crypto.subtle.digest('MD5', data).then((hash) => {
200
+ // Convert ArrayBuffer to hexadecimal string
201
+ return Array.from(new Uint8Array(hash))
202
+ .map((b) => b.toString(16).padStart(2, '0'))
203
+ .join('');
204
+ });
205
+ }
206
+ /**
207
+ * Gravatar source implementation.
208
+ * Fetch avatar source based on gravatar email
209
+ */
210
+ class Gravatar {
211
+ constructor(value) {
212
+ this.value = value;
213
+ this.sourceType = AvatarSource.GRAVATAR;
214
+ // Use regex to check if the value is already an MD5 hash, otherwise calculate it
215
+ if (value.match('^[a-f0-9]{32}$')) {
216
+ this.sourceId = value;
217
+ }
218
+ else {
219
+ hashMD5(value).then((hash) => {
220
+ this.sourceId = hash;
221
+ });
222
+ }
223
+ }
224
+ getAvatar(size) {
225
+ const avatarSize = isRetina() ? size * 2 : size;
226
+ return `https://secure.gravatar.com/avatar/${this.sourceId}?s=${avatarSize}&d=404`;
227
+ }
228
+ }
229
+
230
+ /**
231
+ * Skype source implementation.
232
+ * Fetch avatar source based on skype identifier
233
+ */
234
+ class Skype {
235
+ constructor(sourceId) {
236
+ this.sourceId = sourceId;
237
+ this.sourceType = AvatarSource.SKYPE;
238
+ }
239
+ getAvatar() {
240
+ return `https://api.skype.com/users/${this.sourceId}/profile/avatar`;
241
+ }
242
+ }
243
+
244
+ /**
245
+ * Value source implementation.
246
+ * return the value as avatar
247
+ */
248
+ class Value {
249
+ constructor(sourceId) {
250
+ this.sourceId = sourceId;
251
+ this.sourceType = AvatarSource.VALUE;
252
+ }
253
+ getAvatar() {
254
+ return this.sourceId;
255
+ }
256
+ }
257
+
258
+ /**
259
+ * Vkontakte source implementation.
260
+ * Fetch avatar source based on vkontakte identifier
261
+ * and image size
262
+ */
263
+ const apiVersion = 5.8;
264
+ class Vkontakte extends AsyncSource {
265
+ constructor(sourceId) {
266
+ super(sourceId);
267
+ this.sourceType = AvatarSource.VKONTAKTE;
268
+ }
269
+ getAvatar(size) {
270
+ const imgSize = this.getImageSize(size);
271
+ return `https://api.vk.com/method/users.get?user_id=${this.sourceId}&v=${apiVersion}&fields=${imgSize}`;
272
+ }
273
+ /**
274
+ * extract vkontakte avatar from json data
275
+ */
276
+ processResponse(data) {
277
+ // avatar key property is the size used to generate avatar url
278
+ // size property is always the last key in the response object
279
+ const sizeProperty = Object.keys(data['response'][0]).pop();
280
+ if (!sizeProperty) {
281
+ return null;
282
+ }
283
+ // return avatar src
284
+ return data['response'][0][sizeProperty] || null;
285
+ }
286
+ /**
287
+ * Returns image size related to vkontakte API
288
+ */
289
+ getImageSize(size) {
290
+ if (size <= 50) {
291
+ return 'photo_50';
292
+ }
293
+ if (size <= 100) {
294
+ return 'photo_100';
295
+ }
296
+ if (size <= 200) {
297
+ return 'photo_200';
298
+ }
299
+ return 'photo_max';
300
+ }
301
+ }
302
+
303
+ /**
304
+ * GitHub source implementation.
305
+ * Fetch avatar source based on github identifier
306
+ */
307
+ class Github extends AsyncSource {
308
+ constructor(sourceId) {
309
+ super(sourceId);
310
+ this.sourceType = AvatarSource.GITHUB;
311
+ }
312
+ getAvatar() {
313
+ return `https://api.github.com/users/${this.sourceId}`;
314
+ }
315
+ /**
316
+ * extract github avatar from json data
317
+ */
318
+ processResponse(data, size) {
319
+ if (size) {
320
+ return `${data.avatar_url}&s=${size}`;
321
+ }
322
+ return data.avatar_url;
323
+ }
324
+ }
325
+
326
+ /**
327
+ * Token used to inject the AvatarConfig object
328
+ */
329
+ const AVATAR_CONFIG = new InjectionToken('avatar.config');
330
+
331
+ class AvatarConfigService {
332
+ constructor(userConfig) {
333
+ this.userConfig = userConfig;
334
+ }
335
+ getAvatarSources(defaultSources) {
336
+ if (this.userConfig &&
337
+ this.userConfig.sourcePriorityOrder &&
338
+ this.userConfig.sourcePriorityOrder.length) {
339
+ const uniqueSources = [
340
+ ...new Set(this.userConfig.sourcePriorityOrder)
341
+ ];
342
+ const validSources = uniqueSources.filter((source) => defaultSources.includes(source));
343
+ return [
344
+ ...validSources,
345
+ ...defaultSources.filter((source) => !validSources.includes(source))
346
+ ];
347
+ }
348
+ return defaultSources;
349
+ }
350
+ getAvatarColors(defaultColors) {
351
+ return ((this.userConfig &&
352
+ this.userConfig.colors &&
353
+ this.userConfig.colors.length &&
354
+ this.userConfig.colors) ||
355
+ defaultColors);
356
+ }
357
+ getDisableSrcCache(defaultDisableSrcCache) {
358
+ if (this.userConfig == null ||
359
+ this.userConfig.disableSrcCache == null) {
360
+ return defaultDisableSrcCache;
361
+ }
362
+ else {
363
+ return this.userConfig.disableSrcCache;
364
+ }
365
+ }
366
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: AvatarConfigService, deps: [{ token: AVATAR_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
367
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: AvatarConfigService, providedIn: 'root' }); }
368
+ }
369
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: AvatarConfigService, decorators: [{
370
+ type: Injectable,
371
+ args: [{ providedIn: 'root' }]
372
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
373
+ type: Optional
374
+ }, {
375
+ type: Inject,
376
+ args: [AVATAR_CONFIG]
377
+ }] }] });
378
+
379
+ /**
380
+ * list of Supported avatar sources
381
+ */
382
+ const defaultSources = [
383
+ AvatarSource.FACEBOOK,
384
+ AvatarSource.GOOGLE,
385
+ AvatarSource.TWITTER,
386
+ AvatarSource.INSTAGRAM,
387
+ AvatarSource.VKONTAKTE,
388
+ AvatarSource.SKYPE,
389
+ AvatarSource.GRAVATAR,
390
+ AvatarSource.GITHUB,
391
+ AvatarSource.CUSTOM,
392
+ AvatarSource.INITIALS,
393
+ AvatarSource.VALUE
394
+ ];
395
+ /**
396
+ * list of default colors
397
+ */
398
+ const defaultColors = [
399
+ '#1abc9c',
400
+ '#3498db',
401
+ '#f1c40f',
402
+ '#8e44ad',
403
+ '#e74c3c',
404
+ '#d35400',
405
+ '#2c3e50',
406
+ '#7f8c8d'
407
+ ];
408
+ /**
409
+ * Default disable custom source cache settings
410
+ */
411
+ const defaultDisableSrcCache = false;
412
+ /**
413
+ * Provides utilities methods related to Avatar component
414
+ */
415
+ class AvatarService {
416
+ constructor(http, avatarConfigService) {
417
+ this.http = http;
418
+ this.avatarConfigService = avatarConfigService;
419
+ this.avatarSources = defaultSources;
420
+ this.avatarColors = defaultColors;
421
+ this.failedSources = new Map();
422
+ this.overrideAvatarSources();
423
+ this.overrideAvatarColors();
424
+ }
425
+ fetchAvatar(avatarUrl) {
426
+ return this.http.get(avatarUrl);
427
+ }
428
+ getRandomColor(avatarText) {
429
+ if (!avatarText) {
430
+ return 'transparent';
431
+ }
432
+ const asciiCodeSum = this.calculateAsciiCode(avatarText);
433
+ return this.avatarColors[asciiCodeSum % this.avatarColors.length];
434
+ }
435
+ compareSources(sourceType1, sourceType2) {
436
+ return (this.getSourcePriority(sourceType1) - this.getSourcePriority(sourceType2));
437
+ }
438
+ isSource(source) {
439
+ return this.avatarSources.includes(source);
440
+ }
441
+ isTextAvatar(sourceType) {
442
+ return [AvatarSource.INITIALS, AvatarSource.VALUE].includes(sourceType);
443
+ }
444
+ buildSourceKey(source) {
445
+ return source.sourceType + '-' + source.sourceId;
446
+ }
447
+ sourceHasFailedBefore(source) {
448
+ return this.failedSources.has(this.buildSourceKey(source));
449
+ }
450
+ markSourceAsFailed(source) {
451
+ this.failedSources.set(this.buildSourceKey(source), source);
452
+ }
453
+ overrideAvatarSources() {
454
+ this.avatarSources = this.avatarConfigService.getAvatarSources(defaultSources);
455
+ }
456
+ overrideAvatarColors() {
457
+ this.avatarColors = this.avatarConfigService.getAvatarColors(defaultColors);
458
+ }
459
+ calculateAsciiCode(value) {
460
+ return value
461
+ .split('')
462
+ .map(letter => letter.charCodeAt(0))
463
+ .reduce((previous, current) => previous + current);
464
+ }
465
+ getSourcePriority(sourceType) {
466
+ return this.avatarSources.indexOf(sourceType);
467
+ }
468
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: AvatarService, deps: [{ token: i1.HttpClient }, { token: AvatarConfigService }], target: i0.ɵɵFactoryTarget.Injectable }); }
469
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: AvatarService, providedIn: 'root' }); }
470
+ }
471
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: AvatarService, decorators: [{
472
+ type: Injectable,
473
+ args: [{ providedIn: 'root' }]
474
+ }], ctorParameters: () => [{ type: i1.HttpClient }, { type: AvatarConfigService }] });
475
+
476
+ /**
477
+ * Custom source implementation (with no cache).
478
+ * return custom image as an avatar
479
+ *
480
+ */
481
+ class CustomNoCache {
482
+ constructor(sourceId) {
483
+ this.sourceId = sourceId;
484
+ this.sourceType = AvatarSource.CUSTOM;
485
+ }
486
+ getAvatar() {
487
+ const urlSuffix = Math.random();
488
+ return `${this.sourceId}${this.sourceId.indexOf('?') > -1 ? '&' : '?'}_=${urlSuffix}`;
489
+ }
490
+ }
491
+
492
+ /**
493
+ * Factory class that implements factory method pattern.
494
+ * Used to create Source implementation class based
495
+ * on the source Type
496
+ */
497
+ class SourceFactory {
498
+ constructor(avatarConfigService) {
499
+ this.sources = {};
500
+ const disableSrcCache = avatarConfigService.getDisableSrcCache(defaultDisableSrcCache);
501
+ this.sources[AvatarSource.FACEBOOK] = Facebook;
502
+ this.sources[AvatarSource.TWITTER] = Twitter;
503
+ this.sources[AvatarSource.GOOGLE] = Google;
504
+ this.sources[AvatarSource.INSTAGRAM] = Instagram;
505
+ this.sources[AvatarSource.SKYPE] = Skype;
506
+ this.sources[AvatarSource.GRAVATAR] = Gravatar;
507
+ this.sources[AvatarSource.CUSTOM] = disableSrcCache ? CustomNoCache : Custom;
508
+ this.sources[AvatarSource.INITIALS] = Initials;
509
+ this.sources[AvatarSource.VALUE] = Value;
510
+ this.sources[AvatarSource.VKONTAKTE] = Vkontakte;
511
+ this.sources[AvatarSource.GITHUB] = Github;
512
+ }
513
+ newInstance(sourceType, sourceValue) {
514
+ return new this.sources[sourceType](sourceValue);
515
+ }
516
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: SourceFactory, deps: [{ token: AvatarConfigService }], target: i0.ɵɵFactoryTarget.Injectable }); }
517
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: SourceFactory, providedIn: 'root' }); }
518
+ }
519
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: SourceFactory, decorators: [{
520
+ type: Injectable,
521
+ args: [{ providedIn: 'root' }]
522
+ }], ctorParameters: () => [{ type: AvatarConfigService }] });
523
+
524
+ /**
525
+ * Universal avatar component that
526
+ * generates avatar from different sources
527
+ *
528
+ * export
529
+ * class AvatarComponent
530
+ * implements {OnChanges}
531
+ */
532
+ class AvatarComponent {
533
+ constructor(sourceFactory, avatarService, sanitizer) {
534
+ this.sourceFactory = sourceFactory;
535
+ this.avatarService = avatarService;
536
+ this.sanitizer = sanitizer;
537
+ this.round = true;
538
+ this.size = 50;
539
+ this.textSizeRatio = 3;
540
+ this.fgColor = '#FFF';
541
+ this.style = {};
542
+ this.cornerRadius = 0;
543
+ this.initialsSize = 0;
544
+ this.clickOnAvatar = new EventEmitter();
545
+ this.isAlive = true;
546
+ this.avatarSrc = null;
547
+ this.avatarAlt = null;
548
+ this.avatarText = null;
549
+ this.avatarStyle = {};
550
+ this.hostStyle = {};
551
+ this.currentIndex = -1;
552
+ this.sources = [];
553
+ }
554
+ onAvatarClicked() {
555
+ this.clickOnAvatar.emit(this.sources[this.currentIndex]);
556
+ }
557
+ /**
558
+ * Detect inputs change
559
+ *
560
+ * param {{ [propKey: string]: SimpleChange }} changes
561
+ *
562
+ * memberof AvatarComponent
563
+ */
564
+ ngOnChanges(changes) {
565
+ for (const propName in changes) {
566
+ if (this.avatarService.isSource(propName)) {
567
+ const sourceType = AvatarSource[propName.toUpperCase()];
568
+ const currentValue = changes[propName].currentValue;
569
+ if (currentValue && typeof currentValue === 'string') {
570
+ this.addSource(sourceType, currentValue);
571
+ }
572
+ else {
573
+ const sanitized = this.sanitizer.sanitize(SecurityContext.URL, currentValue);
574
+ if (sanitized) {
575
+ this.addSource(sourceType, sanitized);
576
+ }
577
+ else {
578
+ this.removeSource(sourceType);
579
+ }
580
+ }
581
+ }
582
+ }
583
+ // reinitialize the avatar component when a source property value has changed
584
+ // the fallback system must be re-invoked with the new values.
585
+ this.initializeAvatar();
586
+ }
587
+ /**
588
+ * Fetch avatar source
589
+ *
590
+ * memberOf AvatarComponent
591
+ */
592
+ fetchAvatarSource() {
593
+ const previousSource = this.sources[this.currentIndex];
594
+ if (previousSource) {
595
+ this.avatarService.markSourceAsFailed(previousSource);
596
+ }
597
+ const source = this.findNextSource();
598
+ if (!source) {
599
+ return;
600
+ }
601
+ if (this.avatarService.isTextAvatar(source.sourceType)) {
602
+ this.buildTextAvatar(source);
603
+ this.avatarSrc = null;
604
+ }
605
+ else {
606
+ this.buildImageAvatar(source);
607
+ }
608
+ }
609
+ findNextSource() {
610
+ while (++this.currentIndex < this.sources.length) {
611
+ const source = this.sources[this.currentIndex];
612
+ if (source && !this.avatarService.sourceHasFailedBefore(source)) {
613
+ return source;
614
+ }
615
+ }
616
+ return null;
617
+ }
618
+ ngOnDestroy() {
619
+ this.isAlive = false;
620
+ }
621
+ /**
622
+ * Initialize the avatar component and its fallback system
623
+ */
624
+ initializeAvatar() {
625
+ this.currentIndex = -1;
626
+ if (this.sources.length > 0) {
627
+ this.sortAvatarSources();
628
+ this.fetchAvatarSource();
629
+ this.hostStyle = {
630
+ width: this.size + 'px',
631
+ height: this.size + 'px'
632
+ };
633
+ }
634
+ }
635
+ sortAvatarSources() {
636
+ this.sources.sort((source1, source2) => this.avatarService.compareSources(source1.sourceType, source2.sourceType));
637
+ }
638
+ buildTextAvatar(avatarSource) {
639
+ this.avatarText = avatarSource.getAvatar(+this.initialsSize);
640
+ this.avatarStyle = this.getInitialsStyle(avatarSource.sourceId);
641
+ }
642
+ buildImageAvatar(avatarSource) {
643
+ this.avatarStyle = this.getImageStyle();
644
+ if (avatarSource instanceof AsyncSource) {
645
+ this.fetchAndProcessAsyncAvatar(avatarSource);
646
+ }
647
+ else {
648
+ this.avatarSrc = this.sanitizer.bypassSecurityTrustUrl(avatarSource.getAvatar(+this.size));
649
+ this.avatarAlt = avatarSource.getAvatar(+this.size);
650
+ }
651
+ }
652
+ /**
653
+ *
654
+ * returns initials style
655
+ *
656
+ * memberOf AvatarComponent
657
+ */
658
+ getInitialsStyle(avatarValue) {
659
+ return {
660
+ textAlign: 'center',
661
+ borderRadius: this.round ? '100%' : this.cornerRadius + 'px',
662
+ border: this.borderColor ? '1px solid ' + this.borderColor : '',
663
+ textTransform: 'uppercase',
664
+ color: this.fgColor,
665
+ backgroundColor: this.bgColor
666
+ ? this.bgColor
667
+ : this.avatarService.getRandomColor(avatarValue),
668
+ font: Math.floor(+this.size / this.textSizeRatio) +
669
+ 'px Helvetica, Arial, sans-serif',
670
+ lineHeight: this.size + 'px',
671
+ ...this.style
672
+ };
673
+ }
674
+ /**
675
+ *
676
+ * returns image style
677
+ *
678
+ * memberOf AvatarComponent
679
+ */
680
+ getImageStyle() {
681
+ return {
682
+ maxWidth: '100%',
683
+ borderRadius: this.round ? '50%' : this.cornerRadius + 'px',
684
+ border: this.borderColor ? '1px solid ' + this.borderColor : '',
685
+ width: this.size + 'px',
686
+ height: this.size + 'px',
687
+ ...this.style
688
+ };
689
+ }
690
+ /**
691
+ * Fetch avatar image asynchronously.
692
+ *
693
+ * param {Source} source represents avatar source
694
+ * memberof AvatarComponent
695
+ */
696
+ fetchAndProcessAsyncAvatar(source) {
697
+ if (this.avatarService.sourceHasFailedBefore(source)) {
698
+ return;
699
+ }
700
+ this.avatarService
701
+ .fetchAvatar(source.getAvatar(+this.size))
702
+ .pipe(takeWhile(() => this.isAlive), map((response) => source.processResponse(response, +this.size)))
703
+ .subscribe({
704
+ next: (avatarSrc) => (this.avatarSrc = avatarSrc),
705
+ error: () => {
706
+ this.fetchAvatarSource();
707
+ }
708
+ });
709
+ }
710
+ /**
711
+ * Add avatar source
712
+ *
713
+ * param sourceType avatar source type e.g facebook,twitter, etc.
714
+ * param sourceValue source value e.g facebookId value, etc.
715
+ */
716
+ addSource(sourceType, sourceValue) {
717
+ const source = this.sources.find((s) => s.sourceType === sourceType);
718
+ if (source) {
719
+ source.sourceId = sourceValue;
720
+ }
721
+ else {
722
+ this.sources.push(this.sourceFactory.newInstance(sourceType, sourceValue));
723
+ }
724
+ }
725
+ /**
726
+ * Remove avatar source
727
+ *
728
+ * param sourceType avatar source type e.g facebook,twitter, etc.
729
+ */
730
+ removeSource(sourceType) {
731
+ this.sources = this.sources.filter((source) => source.sourceType !== sourceType);
732
+ }
733
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: AvatarComponent, deps: [{ token: SourceFactory }, { token: AvatarService }, { token: i3.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component }); }
734
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.4", type: AvatarComponent, isStandalone: true, selector: "ng-hub-ui-avatar, hub-avatar", inputs: { round: "round", size: "size", textSizeRatio: "textSizeRatio", bgColor: "bgColor", fgColor: "fgColor", borderColor: "borderColor", style: "style", cornerRadius: "cornerRadius", facebook: ["facebookId", "facebook"], twitter: ["twitterId", "twitter"], google: ["googleId", "google"], instagram: ["instagramId", "instagram"], vkontakte: ["vkontakteId", "vkontakte"], skype: ["skypeId", "skype"], gravatar: ["gravatarId", "gravatar"], github: ["githubId", "github"], custom: ["src", "custom"], customAlt: ["alt", "customAlt"], initials: ["name", "initials"], value: "value", referrerpolicy: "referrerpolicy", placeholder: "placeholder", initialsSize: "initialsSize" }, outputs: { clickOnAvatar: "clickOnAvatar" }, usesOnChanges: true, ngImport: i0, template: `
735
+ <div
736
+ (click)="onAvatarClicked()"
737
+ class="avatar-container"
738
+ [ngStyle]="hostStyle"
739
+ >
740
+ <img
741
+ *ngIf="avatarSrc; else textAvatar"
742
+ [src]="avatarSrc"
743
+ [alt]="customAlt ? customAlt : avatarAlt"
744
+ [width]="size"
745
+ [height]="size"
746
+ [ngStyle]="avatarStyle"
747
+ [referrerPolicy]="referrerpolicy"
748
+ (error)="fetchAvatarSource()"
749
+ class="avatar-content"
750
+ loading="lazy"
751
+ />
752
+ <ng-template #textAvatar>
753
+ <div
754
+ *ngIf="avatarText"
755
+ class="avatar-content"
756
+ [ngStyle]="avatarStyle"
757
+ >
758
+ {{ avatarText }}
759
+ </div>
760
+ </ng-template>
761
+ </div>
762
+ `, isInline: true, styles: [":host{border-radius:50%}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); }
763
+ }
764
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: AvatarComponent, decorators: [{
765
+ type: Component,
766
+ args: [{ selector: 'ng-hub-ui-avatar, hub-avatar', standalone: true, imports: [NgStyle, NgIf], template: `
767
+ <div
768
+ (click)="onAvatarClicked()"
769
+ class="avatar-container"
770
+ [ngStyle]="hostStyle"
771
+ >
772
+ <img
773
+ *ngIf="avatarSrc; else textAvatar"
774
+ [src]="avatarSrc"
775
+ [alt]="customAlt ? customAlt : avatarAlt"
776
+ [width]="size"
777
+ [height]="size"
778
+ [ngStyle]="avatarStyle"
779
+ [referrerPolicy]="referrerpolicy"
780
+ (error)="fetchAvatarSource()"
781
+ class="avatar-content"
782
+ loading="lazy"
783
+ />
784
+ <ng-template #textAvatar>
785
+ <div
786
+ *ngIf="avatarText"
787
+ class="avatar-content"
788
+ [ngStyle]="avatarStyle"
789
+ >
790
+ {{ avatarText }}
791
+ </div>
792
+ </ng-template>
793
+ </div>
794
+ `, styles: [":host{border-radius:50%}\n"] }]
795
+ }], ctorParameters: () => [{ type: SourceFactory }, { type: AvatarService }, { type: i3.DomSanitizer }], propDecorators: { round: [{
796
+ type: Input
797
+ }], size: [{
798
+ type: Input
799
+ }], textSizeRatio: [{
800
+ type: Input
801
+ }], bgColor: [{
802
+ type: Input
803
+ }], fgColor: [{
804
+ type: Input
805
+ }], borderColor: [{
806
+ type: Input
807
+ }], style: [{
808
+ type: Input
809
+ }], cornerRadius: [{
810
+ type: Input
811
+ }], facebook: [{
812
+ type: Input,
813
+ args: ['facebookId']
814
+ }], twitter: [{
815
+ type: Input,
816
+ args: ['twitterId']
817
+ }], google: [{
818
+ type: Input,
819
+ args: ['googleId']
820
+ }], instagram: [{
821
+ type: Input,
822
+ args: ['instagramId']
823
+ }], vkontakte: [{
824
+ type: Input,
825
+ args: ['vkontakteId']
826
+ }], skype: [{
827
+ type: Input,
828
+ args: ['skypeId']
829
+ }], gravatar: [{
830
+ type: Input,
831
+ args: ['gravatarId']
832
+ }], github: [{
833
+ type: Input,
834
+ args: ['githubId']
835
+ }], custom: [{
836
+ type: Input,
837
+ args: ['src']
838
+ }], customAlt: [{
839
+ type: Input,
840
+ args: ['alt']
841
+ }], initials: [{
842
+ type: Input,
843
+ args: ['name']
844
+ }], value: [{
845
+ type: Input
846
+ }], referrerpolicy: [{
847
+ type: Input
848
+ }], placeholder: [{
849
+ type: Input
850
+ }], initialsSize: [{
851
+ type: Input
852
+ }], clickOnAvatar: [{
853
+ type: Output
854
+ }] } });
855
+
856
+ class AvatarModule {
857
+ static forRoot(avatarConfig) {
858
+ return {
859
+ ngModule: AvatarModule,
860
+ providers: [
861
+ {
862
+ provide: AVATAR_CONFIG,
863
+ useValue: avatarConfig ? avatarConfig : {}
864
+ }
865
+ ]
866
+ };
867
+ }
868
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: AvatarModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
869
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.4", ngImport: i0, type: AvatarModule, imports: [CommonModule, AvatarComponent] }); }
870
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: AvatarModule, providers: [SourceFactory, AvatarService, AvatarConfigService], imports: [CommonModule] }); }
871
+ }
872
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: AvatarModule, decorators: [{
873
+ type: NgModule,
874
+ args: [{
875
+ imports: [CommonModule, AvatarComponent],
876
+ declarations: [],
877
+ providers: [SourceFactory, AvatarService, AvatarConfigService],
878
+ exports: []
879
+ }]
880
+ }] });
881
+
882
+ /*
883
+ * Public API Surface of ng-hub-ui-avatar
884
+ */
885
+
886
+ /**
887
+ * Generated bundle index. Do not edit.
888
+ */
889
+
890
+ export { AvatarComponent, AvatarModule, AvatarService, AvatarSource, defaultColors, defaultDisableSrcCache, defaultSources };
891
+ //# sourceMappingURL=ng-hub-ui-avatar.mjs.map