@chat21/chat21-web-widget 5.1.34-rc1 → 5.1.34

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 (193) hide show
  1. package/.github/workflows/docker-community-push-latest.yml +13 -23
  2. package/.github/workflows/docker-image-tag-community-tag-push.yml +12 -22
  3. package/CHANGELOG.md +8 -129
  4. package/Dockerfile +5 -4
  5. package/angular.json +3 -21
  6. package/docs/changelog/this-branch.md +0 -36
  7. package/env.sample +2 -3
  8. package/nginx.conf +2 -22
  9. package/package.json +3 -10
  10. package/src/app/app.component.html +2 -2
  11. package/src/app/app.component.scss +14 -25
  12. package/src/app/app.component.spec.ts +6 -21
  13. package/src/app/app.component.ts +9 -10
  14. package/src/app/app.module.ts +0 -13
  15. package/src/app/component/conversation-detail/conversation/conversation.component.html +11 -25
  16. package/src/app/component/conversation-detail/conversation/conversation.component.scss +2 -40
  17. package/src/app/component/conversation-detail/conversation/conversation.component.spec.ts +75 -644
  18. package/src/app/component/conversation-detail/conversation/conversation.component.ts +14 -100
  19. package/src/app/component/conversation-detail/conversation-audio-recorder/conversation-audio-recorder.component.html +13 -25
  20. package/src/app/component/conversation-detail/conversation-audio-recorder/conversation-audio-recorder.component.spec.ts +5 -123
  21. package/src/app/component/conversation-detail/conversation-audio-recorder/conversation-audio-recorder.component.ts +0 -1
  22. package/src/app/component/conversation-detail/conversation-content/conversation-content.component.html +10 -23
  23. package/src/app/component/conversation-detail/conversation-content/conversation-content.component.scss +1 -19
  24. package/src/app/component/conversation-detail/conversation-content/conversation-content.component.spec.ts +149 -242
  25. package/src/app/component/conversation-detail/conversation-content/conversation-content.component.ts +5 -8
  26. package/src/app/component/conversation-detail/conversation-emojii/conversation-emojii.component.spec.ts +3 -53
  27. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.html +96 -200
  28. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.scss +6 -211
  29. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.spec.ts +78 -452
  30. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.ts +76 -291
  31. package/src/app/component/conversation-detail/conversation-header/conversation-header.component.html +53 -113
  32. package/src/app/component/conversation-detail/conversation-header/conversation-header.component.scss +4 -12
  33. package/src/app/component/conversation-detail/conversation-header/conversation-header.component.spec.ts +29 -274
  34. package/src/app/component/conversation-detail/conversation-internal-frame/conversation-internal-frame.component.html +9 -23
  35. package/src/app/component/conversation-detail/conversation-internal-frame/conversation-internal-frame.component.spec.ts +8 -80
  36. package/src/app/component/conversation-detail/conversation-preview/conversation-preview.component.html +23 -29
  37. package/src/app/component/conversation-detail/conversation-preview/conversation-preview.component.spec.ts +16 -185
  38. package/src/app/component/conversation-detail/conversation-preview/conversation-preview.component.ts +14 -34
  39. package/src/app/component/error-alert/error-alert.component.spec.ts +5 -65
  40. package/src/app/component/eyeeye-catcher-card/eyeeye-catcher-card.component.html +7 -16
  41. package/src/app/component/eyeeye-catcher-card/eyeeye-catcher-card.component.scss +0 -21
  42. package/src/app/component/eyeeye-catcher-card/eyeeye-catcher-card.component.spec.ts +7 -89
  43. package/src/app/component/form/form-builder/form-builder.component.html +1 -1
  44. package/src/app/component/form/form-builder/form-builder.component.spec.ts +21 -163
  45. package/src/app/component/form/inputs/form-checkbox/form-checkbox.component.html +4 -8
  46. package/src/app/component/form/inputs/form-checkbox/form-checkbox.component.scss +5 -10
  47. package/src/app/component/form/inputs/form-checkbox/form-checkbox.component.spec.ts +16 -90
  48. package/src/app/component/form/inputs/form-checkbox/form-checkbox.component.ts +0 -26
  49. package/src/app/component/form/inputs/form-label/form-label.component.spec.ts +11 -45
  50. package/src/app/component/form/inputs/form-radio-button/form-radio-button.component.spec.ts +6 -24
  51. package/src/app/component/form/inputs/form-select/form-select.component.spec.ts +5 -14
  52. package/src/app/component/form/inputs/form-text/form-text.component.html +12 -14
  53. package/src/app/component/form/inputs/form-text/form-text.component.scss +1 -11
  54. package/src/app/component/form/inputs/form-text/form-text.component.spec.ts +17 -113
  55. package/src/app/component/form/inputs/form-text/form-text.component.ts +3 -35
  56. package/src/app/component/form/inputs/form-textarea/form-textarea.component.html +11 -13
  57. package/src/app/component/form/inputs/form-textarea/form-textarea.component.scss +5 -6
  58. package/src/app/component/form/inputs/form-textarea/form-textarea.component.spec.ts +13 -149
  59. package/src/app/component/form/inputs/form-textarea/form-textarea.component.ts +0 -26
  60. package/src/app/component/form/prechat-form/prechat-form.component.html +11 -14
  61. package/src/app/component/form/prechat-form/prechat-form.component.spec.ts +10 -102
  62. package/src/app/component/form/prechat-form/prechat-form.component.ts +1 -8
  63. package/src/app/component/home/home.component.html +31 -38
  64. package/src/app/component/home/home.component.scss +2 -4
  65. package/src/app/component/home/home.component.spec.ts +11 -226
  66. package/src/app/component/home-conversations/home-conversations.component.html +26 -30
  67. package/src/app/component/home-conversations/home-conversations.component.scss +0 -3
  68. package/src/app/component/home-conversations/home-conversations.component.spec.ts +36 -212
  69. package/src/app/component/last-message/last-message.component.html +9 -15
  70. package/src/app/component/last-message/last-message.component.scss +2 -16
  71. package/src/app/component/last-message/last-message.component.spec.ts +23 -204
  72. package/src/app/component/last-message/last-message.component.ts +1 -4
  73. package/src/app/component/launcher-button/launcher-button.component.html +13 -8
  74. package/src/app/component/launcher-button/launcher-button.component.spec.ts +8 -104
  75. package/src/app/component/list-all-conversations/list-all-conversations.component.html +17 -12
  76. package/src/app/component/list-all-conversations/list-all-conversations.component.scss +0 -2
  77. package/src/app/component/list-conversations/list-conversations.component.html +22 -22
  78. package/src/app/component/menu-options/menu-options.component.html +20 -30
  79. package/src/app/component/menu-options/menu-options.component.spec.ts +9 -125
  80. package/src/app/component/message/audio/audio.component.html +15 -13
  81. package/src/app/component/message/audio/audio.component.spec.ts +5 -140
  82. package/src/app/component/message/audio/audio.component.ts +5 -1
  83. package/src/app/component/message/avatar/avatar.component.html +2 -2
  84. package/src/app/component/message/avatar/avatar.component.spec.ts +7 -99
  85. package/src/app/component/message/bubble-message/bubble-message.component.html +51 -38
  86. package/src/app/component/message/bubble-message/bubble-message.component.scss +1 -54
  87. package/src/app/component/message/bubble-message/bubble-message.component.spec.ts +57 -154
  88. package/src/app/component/message/bubble-message/bubble-message.component.ts +11 -89
  89. package/src/app/component/message/buttons/action-button/action-button.component.html +4 -3
  90. package/src/app/component/message/buttons/action-button/action-button.component.spec.ts +5 -49
  91. package/src/app/component/message/buttons/link-button/link-button.component.scss +8 -5
  92. package/src/app/component/message/buttons/link-button/link-button.component.spec.ts +5 -50
  93. package/src/app/component/message/buttons/text-button/text-button.component.spec.ts +5 -44
  94. package/src/app/component/message/carousel/carousel.component.html +16 -29
  95. package/src/app/component/message/carousel/carousel.component.scss +8 -20
  96. package/src/app/component/message/carousel/carousel.component.spec.ts +3 -80
  97. package/src/app/component/message/carousel/carousel.component.ts +0 -16
  98. package/src/app/component/message/frame/frame.component.html +4 -9
  99. package/src/app/component/message/frame/frame.component.spec.ts +15 -34
  100. package/src/app/component/message/frame/frame.component.ts +2 -7
  101. package/src/app/component/message/html/html.component.html +1 -1
  102. package/src/app/component/message/html/html.component.scss +1 -1
  103. package/src/app/component/message/html/html.component.spec.ts +7 -24
  104. package/src/app/component/message/image/image.component.html +10 -12
  105. package/src/app/component/message/image/image.component.scss +0 -16
  106. package/src/app/component/message/image/image.component.spec.ts +15 -101
  107. package/src/app/component/message/image/image.component.ts +51 -90
  108. package/src/app/component/message/info-message/info-message.component.spec.ts +14 -26
  109. package/src/app/component/message/like-unlike/like-unlike.component.html +9 -7
  110. package/src/app/component/message/like-unlike/like-unlike.component.spec.ts +3 -31
  111. package/src/app/component/message/return-receipt/return-receipt.component.spec.ts +17 -38
  112. package/src/app/component/message/text/text.component.html +3 -3
  113. package/src/app/component/message/text/text.component.scss +86 -80
  114. package/src/app/component/message/text/text.component.spec.ts +13 -106
  115. package/src/app/component/message-attachment/message-attachment.component.spec.ts +13 -134
  116. package/src/app/component/selection-department/selection-department.component.html +23 -21
  117. package/src/app/component/selection-department/selection-department.component.spec.ts +14 -159
  118. package/src/app/component/selection-department/selection-department.component.ts +1 -8
  119. package/src/app/component/send-button/send-button.component.html +13 -5
  120. package/src/app/component/send-button/send-button.component.spec.ts +2 -2
  121. package/src/app/component/star-rating-widget/star-rating-widget.component.html +81 -51
  122. package/src/app/directives/tooltip.directive.spec.ts +4 -8
  123. package/src/app/modals/confirm-close/confirm-close.component.html +8 -20
  124. package/src/app/modals/confirm-close/confirm-close.component.scss +0 -3
  125. package/src/app/modals/confirm-close/confirm-close.component.spec.ts +4 -13
  126. package/src/app/modals/confirm-close/confirm-close.component.ts +1 -8
  127. package/src/app/pipe/html-entites-encode.pipe.spec.ts +2 -35
  128. package/src/app/pipe/marked.pipe.spec.ts +2 -38
  129. package/src/app/pipe/marked.pipe.ts +41 -51
  130. package/src/app/providers/app-config.service.ts +2 -4
  131. package/src/app/providers/brand.service.spec.ts +2 -23
  132. package/src/app/providers/brand.service.ts +1 -1
  133. package/src/app/providers/global-settings.service.spec.ts +14 -1009
  134. package/src/app/providers/global-settings.service.ts +2 -82
  135. package/src/app/providers/translator.service.ts +6 -26
  136. package/src/app/sass/_variables.scss +0 -3
  137. package/src/app/sass/animations.scss +1 -19
  138. package/src/app/utils/globals.ts +1 -21
  139. package/src/app/utils/utils-resources.ts +1 -1
  140. package/src/assets/i18n/en.json +99 -106
  141. package/src/assets/i18n/es.json +100 -107
  142. package/src/assets/i18n/fr.json +100 -107
  143. package/src/assets/i18n/it.json +98 -107
  144. package/src/assets/twp/index-dev.html +0 -18
  145. package/src/chat21-core/models/message.ts +1 -2
  146. package/src/chat21-core/providers/firebase/firebase-conversation-handler.ts +2 -3
  147. package/src/chat21-core/providers/mqtt/mqtt-conversation-handler.ts +0 -12
  148. package/src/chat21-core/providers/scripts/script.service.spec.ts +2 -12
  149. package/src/chat21-core/providers/tiledesk/tiledesk-requests.service.ts +1 -1
  150. package/src/chat21-core/utils/utils-message.ts +0 -7
  151. package/src/chat21-core/utils/utils.ts +2 -5
  152. package/src/widget-config-template.json +1 -4
  153. package/src/widget-config.json +1 -4
  154. package/tsconfig.json +0 -5
  155. package/.angular-mcp-cache/package.json +0 -1
  156. package/.cursor/angular18-accessibility-auditor-skill.md +0 -442
  157. package/.cursor/mcp.json +0 -15
  158. package/.github/workflows/build.yml +0 -22
  159. package/.github/workflows/playwright.yml +0 -27
  160. package/mocks/voice-websocket-mock/server.cjs +0 -245
  161. package/playwright.config.ts +0 -41
  162. package/src/app/component/conversation-detail/stream-audio-spectrum/stream-audio-spectrum.component.html +0 -46
  163. package/src/app/component/conversation-detail/stream-audio-spectrum/stream-audio-spectrum.component.scss +0 -83
  164. package/src/app/component/conversation-detail/stream-audio-spectrum/stream-audio-spectrum.component.ts +0 -192
  165. package/src/app/component/form/prechat-form-test-mock.ts +0 -35
  166. package/src/app/component/message/audio-sync/audio-sync.component.html +0 -18
  167. package/src/app/component/message/audio-sync/audio-sync.component.scss +0 -65
  168. package/src/app/component/message/audio-sync/audio-sync.component.spec.ts +0 -103
  169. package/src/app/component/message/audio-sync/audio-sync.component.ts +0 -643
  170. package/src/app/providers/tts-audio-playback-coordinator.service.spec.ts +0 -117
  171. package/src/app/providers/tts-audio-playback-coordinator.service.ts +0 -109
  172. package/src/app/providers/voice/STT&TTS/openai-voice.config.ts +0 -12
  173. package/src/app/providers/voice/STT&TTS/openai-voice.provider.ts +0 -171
  174. package/src/app/providers/voice/STT&TTS/speech-provider.abstract.ts +0 -39
  175. package/src/app/providers/voice/audio.types.ts +0 -40
  176. package/src/app/providers/voice/vad.service.spec.ts +0 -28
  177. package/src/app/providers/voice/vad.service.ts +0 -70
  178. package/src/app/providers/voice/voice-streaming.service.spec.ts +0 -23
  179. package/src/app/providers/voice/voice-streaming.service.ts +0 -702
  180. package/src/app/providers/voice/voice-streaming.types.ts +0 -112
  181. package/src/app/providers/voice/voice.service.spec.ts +0 -227
  182. package/src/app/providers/voice/voice.service.ts +0 -973
  183. package/src/app/shims/onnxruntime-web-wasm.ts +0 -4
  184. package/src/assets/onnx/ort-wasm-simd-threaded.mjs +0 -59
  185. package/src/assets/onnx/ort-wasm-simd-threaded.wasm +0 -0
  186. package/src/assets/sounds/keyboard.mp3 +0 -0
  187. package/src/assets/twp/tiledesk_widget_files/widget-css-override-example.css +0 -14
  188. package/src/assets/vad/silero_vad_legacy.onnx +0 -0
  189. package/src/assets/vad/vad.worklet.bundle.min.js +0 -1
  190. package/src/chat21-core/providers/chat-manager.spec.ts +0 -72
  191. package/tests/widget-form-rich.spec.ts +0 -67
  192. package/tests/widget-index-dev-settings.spec.ts +0 -52
  193. package/tests/widget-twp-iframe.spec.ts +0 -39
@@ -21,22 +21,6 @@ img {
21
21
  transform: scale(1.05);
22
22
  }
23
23
 
24
- .c21-image-trigger {
25
- display: block;
26
- padding: 0;
27
- margin: 0;
28
- background: transparent;
29
- border: none;
30
- border-radius: var(--borderRadius);
31
- width: 100%;
32
- cursor: pointer;
33
- line-height: 0;
34
- }
35
- .c21-image-trigger:focus-visible {
36
- outline: 2px solid var(--c21-focus-ring, #1a73e8);
37
- outline-offset: 2px;
38
- }
39
-
40
24
 
41
25
  .c21-img-container {
42
26
  text-align: center;
@@ -1,5 +1,4 @@
1
- import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
2
- import * as FileSaver from 'file-saver';
1
+ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
3
2
 
4
3
  import { ImageComponent } from './image.component';
5
4
 
@@ -7,115 +6,30 @@ describe('ImageComponent', () => {
7
6
  let component: ImageComponent;
8
7
  let fixture: ComponentFixture<ImageComponent>;
9
8
 
10
- const metadata = {
11
- height: 100,
12
- name: 'logo_fb.png',
13
- src: 'https://cdn.example.com/logo.png',
14
- type: 'image/png',
15
- uid: 'u1',
16
- width: 100,
17
- };
18
-
19
- beforeEach(waitForAsync(() => {
9
+ beforeEach(async(() => {
20
10
  TestBed.configureTestingModule({
21
- declarations: [ImageComponent],
22
- }).compileComponents();
11
+ declarations: [ ImageComponent ]
12
+ })
13
+ .compileComponents();
23
14
  }));
24
15
 
25
16
  beforeEach(() => {
26
17
  fixture = TestBed.createComponent(ImageComponent);
27
18
  component = fixture.componentInstance;
28
- component.metadata = { ...metadata };
29
- component.width = 80;
30
- component.height = 80;
19
+ component.metadata = {
20
+ height: 650,
21
+ name: "logo_fb.png",
22
+ src: "https://firebasestorage.googleapis.com/v0/b/chat21-pre-01.appspot.com/o/public%2Fimages%2F42083ab3-3aa6-4507-831c-41c84b09dd83%2F0e8e8562-360e-4407-aa20-a0ccbe99b62d%2Flogo_fb.png?alt=media&token=8125435a-76ac-42f0-9017-cf3d8fb4e8a1",
23
+ type: "image/png",
24
+ uid: "ksg7sxnt",
25
+ width: 650
26
+ }
27
+ component.width = 650
28
+ component.height = 650
31
29
  fixture.detectChanges();
32
30
  });
33
31
 
34
32
  it('should create', () => {
35
33
  expect(component).toBeTruthy();
36
34
  });
37
-
38
- it('ngOnInit should run', () => {
39
- expect(() => component.ngOnInit()).not.toThrow();
40
- });
41
-
42
- it('onLoaded should clear loading and emit', () => {
43
- spyOn(component.onElementRendered, 'emit');
44
- component.loading = true;
45
- component.onLoaded({} as any);
46
- expect(component.loading).toBe(false);
47
- expect(component.onElementRendered.emit).toHaveBeenCalledWith({ element: 'image', status: true });
48
- });
49
-
50
- it('downloadImage should call saveAs with explicit fileName', () => {
51
- spyOn(FileSaver, 'saveAs');
52
- component.downloadImage('https://cdn/x/a.png', 'out.png');
53
- expect(FileSaver.saveAs).toHaveBeenCalledWith('https://cdn/x/a.png', 'out.png');
54
- });
55
-
56
- it('downloadImage should derive fileName from URL when omitted', () => {
57
- spyOn(FileSaver, 'saveAs');
58
- const url = 'https://cdn/x/my%20file.png';
59
- component.downloadImage(url, null as any);
60
- expect(FileSaver.saveAs).toHaveBeenCalled();
61
- const name = (FileSaver.saveAs as jasmine.Spy).calls.mostRecent().args[1] as string;
62
- expect(name).toContain('my');
63
- });
64
-
65
- it('onClickImage onload should register keydown on iframe document and close on Escape', () => {
66
- const origCreate = document.createElement.bind(document);
67
- const origGetById = document.getElementById.bind(document);
68
- const fakeIframe: any = {
69
- setAttribute: jasmine.createSpy('setAttribute'),
70
- style: {},
71
- srcdoc: '',
72
- onload: null as null | ((ev: Event) => void),
73
- };
74
- spyOn(document, 'createElement').and.callFake((tag: string) => (tag === 'iframe' ? fakeIframe : origCreate(tag)));
75
- spyOn(document, 'getElementById').and.callFake((id: string) =>
76
- id === 'tiledesk-image-preview' ? fakeIframe : origGetById(id),
77
- );
78
- spyOn(document.body, 'appendChild').and.callFake((node: any) => {
79
- node.parentNode = document.body;
80
- return node;
81
- });
82
- spyOn(document.body, 'removeChild').and.stub();
83
- component.onClickImage();
84
- const docMock: any = {
85
- getElementById: jasmine.createSpy('getElementById').and.returnValue(null),
86
- addEventListener: jasmine.createSpy('addEventListener'),
87
- };
88
- fakeIframe.contentWindow = { document: docMock };
89
- expect(fakeIframe.onload).toBeTruthy();
90
- fakeIframe.onload({} as any);
91
- expect(docMock.addEventListener).toHaveBeenCalledWith('keydown', jasmine.any(Function));
92
- const keydownHandler = docMock.addEventListener.calls.mostRecent().args[1] as (e: KeyboardEvent) => void;
93
- keydownHandler({ key: 'Escape', keyCode: 27, preventDefault: jasmine.createSpy() } as any);
94
- expect(document.body.removeChild).toHaveBeenCalledWith(fakeIframe);
95
- });
96
-
97
- it('onClickImage should append iframe with preview markup', () => {
98
- const iframes: HTMLIFrameElement[] = [];
99
- const origCreate = document.createElement.bind(document);
100
- spyOn(document, 'createElement').and.callFake((tag: string) => {
101
- const el = origCreate(tag) as HTMLElement;
102
- if (tag === 'iframe') {
103
- iframes.push(el as HTMLIFrameElement);
104
- }
105
- return el;
106
- });
107
- spyOn(document.body, 'appendChild').and.callThrough();
108
- component.onClickImage();
109
- expect(document.body.appendChild).toHaveBeenCalled();
110
- expect(iframes.length).toBe(1);
111
- expect(iframes[0].id).toBe('tiledesk-image-preview');
112
- expect(iframes[0].srcdoc).toContain('tiledesk-popup');
113
- expect(iframes[0].srcdoc).toContain(metadata.src);
114
- document.body.removeChild(iframes[0]);
115
- });
116
-
117
- it('img should expose alt from metadata name', () => {
118
- const img = (fixture.nativeElement as HTMLElement).querySelector('img');
119
- expect(img?.getAttribute('alt')).toBe('logo_fb.png');
120
- });
121
35
  });
@@ -42,99 +42,60 @@ export class ImageComponent implements OnInit {
42
42
  // this.onClickImage()
43
43
  }
44
44
 
45
- /**
46
- * Opens the image in an accessible lightbox.
47
- *
48
- * Accessibility features (WCAG 2.1.1, 2.1.2, 2.4.3, 4.1.2):
49
- * - Lightbox container is rendered as role="dialog" aria-modal="true" with aria-label.
50
- * - A real <button> with aria-label closes the dialog.
51
- * - The dialog can be dismissed via Escape, click on the backdrop, or the close button.
52
- * - The previously focused element is restored when the lightbox closes.
53
- * - Focus is moved to the close button on open to keep keyboard users inside the dialog.
54
- */
55
45
  onClickImage(){
56
- const previouslyFocused = document.activeElement as HTMLElement | null;
57
- const altText = this.metadata?.name || 'Image preview';
58
- const closeLabel = this.tooltipMessage || 'Close';
59
-
60
- const ifrm = document.createElement('iframe');
61
- ifrm.setAttribute('frameborder', '0');
62
- ifrm.setAttribute('id', 'tiledesk-image-preview');
63
- ifrm.setAttribute('tiledesk_context', 'parent');
64
- ifrm.setAttribute('title', altText);
65
- ifrm.setAttribute('aria-label', altText);
66
- ifrm.setAttribute('style', 'width: 100%; height: 100%; position: absolute; z-index: 2147483003; border: 0;');
67
-
68
- let iframeContent = '<!doctype html><html lang="' + (document.documentElement.lang || 'en') + '"><head>';
69
- iframeContent += '<meta charset="utf-8"/>';
70
- iframeContent += '<title>' + altText.replace(/[<>]/g, '') + '</title>';
71
- iframeContent += '<style>';
72
- iframeContent += 'html,body{margin:0;padding:0;height:100%;}';
73
- iframeContent += '.tiledesk-popup-backdrop{position:fixed;inset:0;background-color:rgba(0,0,0,0.6);}';
74
- iframeContent += '.tiledesk-popup-content{position:fixed;inset:0;display:flex;justify-content:center;align-items:center;padding:32px;}';
75
- iframeContent += '.tiledesk-popup-image{max-height:85vh;max-width:90vw;border-radius:8px;}';
76
- iframeContent += '.tiledesk-popup-button{position:fixed;top:16px;right:16px;width:40px;height:40px;display:flex;align-items:center;justify-content:center;background-color:rgba(255,255,255,0.95);border:1px solid rgba(0,0,0,0.1);border-radius:50%;cursor:pointer;padding:0;}';
77
- iframeContent += '.tiledesk-popup-button:focus-visible{outline:3px solid #1a73e8;outline-offset:2px;}';
78
- iframeContent += '.tiledesk-popup-button svg{width:20px;height:20px;fill:#000;}';
79
- iframeContent += '@media (prefers-reduced-motion: reduce){.tiledesk-popup-backdrop{transition:none;}}';
80
- iframeContent += '</style></head><body>';
81
- iframeContent += '<div role="dialog" aria-modal="true" aria-label="' + altText.replace(/"/g, '&quot;') + '" id="frame-root">';
82
- iframeContent += '<div class="tiledesk-popup-backdrop" id="popup-backdrop"></div>';
83
- iframeContent += '<div class="tiledesk-popup-content">';
84
- iframeContent += '<img src="' + this.metadata.src + '" class="tiledesk-popup-image" id="image-popup" alt="' + altText.replace(/"/g, '&quot;') + '">';
85
- iframeContent += '</div>';
86
- iframeContent += '<button type="button" id="closeButton" class="tiledesk-popup-button" aria-label="' + closeLabel.replace(/"/g, '&quot;') + '">';
87
- iframeContent += '<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>';
88
- iframeContent += '</button>';
89
- iframeContent += '</div>';
90
- iframeContent += '</body></html>';
91
-
92
- ifrm.srcdoc = iframeContent;
93
- window.document.body.appendChild(ifrm);
94
-
95
- const closeLightbox = () => {
96
- const node = window.document.getElementById('tiledesk-image-preview');
97
- if (node && node.parentNode) {
98
- node.parentNode.removeChild(node);
99
- }
100
- if (previouslyFocused && typeof previouslyFocused.focus === 'function') {
101
- try { previouslyFocused.focus(); } catch(e) { /* noop */ }
102
- }
103
- };
104
-
105
- ifrm.onload = function () {
106
- const doc = ifrm.contentWindow?.document;
107
- if (!doc) { return; }
108
-
109
- const closeBtn = doc.getElementById('closeButton') as HTMLButtonElement | null;
110
- const backdrop = doc.getElementById('popup-backdrop');
111
- const image = doc.getElementById('image-popup');
112
-
113
- if (closeBtn) {
114
- closeBtn.addEventListener('click', (e) => {
115
- e.preventDefault();
116
- e.stopPropagation();
117
- closeLightbox();
118
- });
119
- closeBtn.focus();
120
- }
121
-
122
- if (backdrop) {
123
- backdrop.addEventListener('click', () => closeLightbox());
124
- }
125
-
126
- if (image) {
127
- image.addEventListener('click', (e) => e.stopPropagation());
128
- }
129
-
130
- // Escape key handler from inside the lightbox iframe
131
- doc.addEventListener('keydown', (event: KeyboardEvent) => {
132
- if (event.key === 'Escape' || event.keyCode === 27) {
133
- event.preventDefault();
134
- closeLightbox();
135
- }
46
+ const that = this;
47
+ var ifrm = document.createElement("iframe");
48
+ ifrm.setAttribute("frameborder", "0");
49
+ // ifrm.setAttribute("border", "0");
50
+ ifrm.setAttribute('id','tiledesk-image-preview');
51
+ ifrm.setAttribute('tiledesk_context','parent');
52
+ ifrm.setAttribute('style', 'width: 100%; height: 100%; position: absolute; z-index: 2147483003;')
53
+
54
+ var iframeContent = '<head>'
55
+ iframeContent += '<style> .tiledesk-popup {position: absolute; inset: 1px; outline-offset: -5px; background-color: rgba(0, 0, 0, 0.35); border-radius:16px; will-change: opacity;}'
56
+ iframeContent += '.tiledesk-popup-content { position: fixed; inset: 0px; width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; outline: 0px;}'
57
+ iframeContent += '.tiledesk-popup-button { display: flex; align-items: center; justify-content: center; width: 35px; height: 35px; position: absolute; top: 0px; right: 0px; background-color: transparent; border: none; cursor: pointer; margin: 9px; padding: 0px; }'
58
+ iframeContent += '.tiledesk-popup-image { max-height: 80vh; max-width: 80vw; }'
59
+ iframeContent += '</style>'
60
+ iframeContent += '</head>';
61
+ iframeContent += '<body>'
62
+ iframeContent += '<div class="frame-root" id="frame-root">'
63
+ iframeContent += '<div class="frame-content">'
64
+ iframeContent += '<div class="tiledesk-popup" style="opacity: 1;"></div>'
65
+ iframeContent += '<div role="button" tabindex="-1" class="tiledesk-popup-content">'
66
+ // iframeContent += '<button id="button" type="button" data-testid="closeButton" class="tiledesk-popup-button">'
67
+ // iframeContent += '<svg id="ic_close" fill="#000000" height="20" viewBox="0 0 24 24" width="20" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg>'
68
+ // iframeContent += '</button>'
69
+ iframeContent += '<a href="'+this.metadata.src+'" data-testid="popupImage-wrapper" class="tidio-popup-vgwcqv" style="opacity: 1; transform: translate3d(0px, 0px, 0px);">'
70
+ iframeContent += '<img src="'+this.metadata.src+'" class="tiledesk-popup-image" id="image-popup">'
71
+ iframeContent += '</a>'
72
+ iframeContent += '</div>'
73
+ iframeContent += '</div>'
74
+ iframeContent +='</body>'
75
+
76
+ // ifrm.src = 'data:text/html;charset=utf-8,' + encodeURI(iframeContent);
77
+ ifrm.srcdoc = iframeContent
78
+ window.document.body.appendChild(ifrm)
79
+
80
+
81
+ ifrm.onload = function(ev) {
82
+ var iframe = window.document.getElementById('tiledesk-image-preview')
83
+ // var button = ifrm.contentWindow.document.getElementById("button");
84
+ // button.addEventListener("click", function(event){
85
+ // window.document.body.removeChild(iframe)
86
+ // });
87
+ var div = ifrm.contentWindow.document.getElementById('frame-root')
88
+ div.addEventListener("click", function(event){
89
+ window.document.body.removeChild(iframe)
136
90
  });
91
+ // var image = ifrm.contentWindow.document.getElementById('image-popup')
92
+ // image.addEventListener("click", function(event){
93
+ // event.preventDefault();
94
+ // event.stopPropagation();
95
+ // that.downloadImage(that.metadata.src, that.metadata.name)
96
+ // });
137
97
  };
98
+
138
99
  }
139
100
 
140
101
 
@@ -1,48 +1,36 @@
1
+ import { CustomLogger } from './../../../../chat21-core/providers/logger/customLogger';
2
+ import { LoggerInstance } from './../../../../chat21-core/providers/logger/loggerInstance';
3
+ import { LoggerService } from 'src/chat21-core/providers/abstract/logger.service';
1
4
  import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
2
-
3
- import { MessageModel } from 'src/chat21-core/models/message';
4
- import { LoggerInstance } from 'src/chat21-core/providers/logger/loggerInstance';
5
- import { CustomLogger } from 'src/chat21-core/providers/logger/customLogger';
6
- import { NGXLogger } from 'ngx-logger';
7
- import { TooltipDirective } from '../../../directives/tooltip.directive';
8
- import { DateAgoPipe } from '../../../pipe/date-ago.pipe';
9
5
  import { MarkedPipe } from '../../../pipe/marked.pipe';
6
+
10
7
  import { InfoMessageComponent } from './info-message.component';
8
+ import { NGXLogger } from 'ngx-logger';
11
9
 
12
10
  describe('InfoMessageComponent', () => {
13
11
  let component: InfoMessageComponent;
14
12
  let fixture: ComponentFixture<InfoMessageComponent>;
15
- const ngxlogger = jasmine.createSpyObj('NGXLogger', ['log', 'trace', 'debug', 'warn', 'error', 'info']);
16
- const customLogger = new CustomLogger(ngxlogger);
13
+ let ngxlogger: NGXLogger;
14
+ let customLogger = new CustomLogger(ngxlogger)
17
15
 
18
16
  beforeEach(waitForAsync(() => {
19
- LoggerInstance.setInstance(customLogger);
20
17
  TestBed.configureTestingModule({
21
- declarations: [InfoMessageComponent, MarkedPipe, DateAgoPipe, TooltipDirective],
22
- }).compileComponents();
18
+ declarations: [ InfoMessageComponent, MarkedPipe ],
19
+ providers: [LoggerService, NGXLogger]
20
+ })
21
+ .compileComponents();
23
22
  }));
24
23
 
25
24
  beforeEach(() => {
26
25
  fixture = TestBed.createComponent(InfoMessageComponent);
27
26
  component = fixture.componentInstance;
28
- component.message = { text: 'hello', timestamp: Date.now() } as MessageModel;
27
+ LoggerInstance.setInstance(customLogger)
28
+ let logger = LoggerInstance.getInstance()
29
+ component['logger']= logger
29
30
  fixture.detectChanges();
30
31
  });
31
32
 
32
33
  it('should create', () => {
33
34
  expect(component).toBeTruthy();
34
35
  });
35
-
36
- it('ngOnInit should replace br tags with newlines in message text', () => {
37
- const msg = { text: 'a<br/>b<br>c', timestamp: Date.now() } as MessageModel;
38
- component.message = { ...msg };
39
- component.ngOnInit();
40
- expect(component.message.text).toContain('\n');
41
- expect(component.message.text).not.toContain('<br');
42
- });
43
-
44
- it('ngOnInit should tolerate missing message', () => {
45
- component.message = undefined as any;
46
- expect(() => component.ngOnInit()).not.toThrow();
47
- });
48
36
  });
@@ -1,19 +1,21 @@
1
1
  <div class="like-container">
2
2
  <div class="menu">
3
3
  <!-- LIKE -->
4
- <button type="button" class="c21-button-clean c21-like" (click)="onClick('like')" aria-label="Like message">
5
- <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
6
- width="24" height="24" viewBox="0 0 24 24" xml:space="preserve" aria-hidden="true" focusable="false">
4
+ <button class="c21-button-clean c21-like" (click)="onClick('like')">
5
+ <svg role="img" aria-labelledby="altIconTitle" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
6
+ width="24" height="24" viewBox="0 0 24 24" xml:space="preserve">
7
7
  <path fill="black" d="M4.5,9h-3C0.7,9,0,9.6,0,10.4v10.4c0,0.8,0.7,1.5,1.5,1.5h3c0.8,0,1.5-0.7,1.5-1.5V10.5C6,9.7,5.3,9,4.5,9z"/>
8
8
  <path fill="black" d="M24,10.5c-0.1-1.7-1.6-3-3.3-3h-4.5c0,0,0,0,0,0c0.4-1.2,0.7-2.2,0.7-2.7c0-1.6-1.2-3.2-3.3-3.2 c-2.2,0-2.8,1.5-3.3,2.7C8.8,8,7.5,7.4,7.5,8.6c0,0.6,0.5,1.1,1.1,1.1c0.2,0,0.5-0.1,0.7-0.2c3.6-2.9,2.7-5.8,4.3-5.8 c0.8,0,1,0.6,1,1c0,0.3-0.4,1.9-1.2,3.4c-0.1,0.2-0.1,0.4-0.1,0.5c0,0.7,0.5,1.1,1.1,1.1h6.5c0.5,0,0.9,0.4,0.9,0.9 c0,0.5-0.4,0.8-0.8,0.9c-0.6,0-1,0.5-1,1.1c0,0.7,0.5,0.7,0.5,1.4c0,1.2-1.6,0.6-1.6,2c0,0.5,0.3,0.6,0.3,1c0,1.1-1.4,0.6-1.4,1.9 c0,0.1,0,0.2,0,0.2c0.1,0.6-0.3,1.1-0.9,1.1l-2.4,0c-1.2,0-2.4-0.4-3.4-1.1l-1.7-1.3c-0.2-0.2-0.4-0.2-0.7-0.2 c-0.6,0-1.1,0.5-1.1,1.1c0,0.3,0.2,0.7,0.4,0.9l1.7,1.3c1.4,1,3,1.6,4.7,1.6h2.5c1.7,0,3-1.3,3.1-2.9c0,0,0,0,0,0 c0.8-0.6,1.3-1.5,1.3-2.6c0-0.1,0-0.3,0-0.4c0.8-0.6,1.4-1.5,1.4-2.6c0-0.2,0-0.5-0.1-0.7C23.5,12.6,24.1,11.6,24,10.5z"/>
9
- </svg>
9
+ <title id="altIconTitle">LIKE</title>
10
+ </svg>
10
11
  </button>
11
12
  <!-- UNLIKE -->
12
- <button type="button" class="c21-button-clean" (click)="onClick('unlike')" aria-label="Unlike message">
13
- <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
14
- width="24" height="24" viewBox="0 0 24 24" xml:space="preserve" aria-hidden="true" focusable="false">
13
+ <button class="c21-button-clean" (click)="onClick('like')">
14
+ <svg role="img" aria-labelledby="altIconTitle" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
15
+ width="24" height="24" viewBox="0 0 24 24" xml:space="preserve">
15
16
  <path d="M6,13.5V3c0-0.8-0.7-1.5-1.5-1.5h-3C0.7,1.5,0,2.2,0,3v10.5c0,0.8,0.7,1.5,1.5,1.5h3C5.3,15,6,14.3,6,13.5z"/>
16
17
  <path d="M22.6,10.7c0.1-0.2,0.1-0.5,0.1-0.7c0-1.1-0.5-2-1.4-2.6c0-0.1,0-0.3,0-0.4c0-1-0.5-2-1.4-2.6c-0.1-1.6-1.5-2.9-3.1-2.9 h-2.5c-1.7,0-3.4,0.6-4.7,1.6L8,4.4C7.7,4.6,7.5,4.9,7.5,5.3c0,0.6,0.5,1.1,1.1,1.1c0.2,0,0.5-0.1,0.7-0.2L11,4.9 c1-0.7,2.2-1.1,3.4-1.1h2.5c0.5,0,0.9,0.4,0.9,0.9c0,0.2-0.1,0.2-0.1,0.4c0,1.3,1.4,0.8,1.4,1.9c0,0.4-0.3,0.5-0.3,1 c0,0.7,0.5,1,0.9,1.1c0.4,0.1,0.7,0.4,0.7,0.9c0,0.6-0.5,0.6-0.5,1.4c0,0.6,0.5,1.1,1,1.1c0.5,0,0.8,0.4,0.8,0.8 c0,0.5-0.4,0.9-0.9,0.9h-6.5c-0.6,0-1.1,0.5-1.1,1.1c0,0.2,0,0.4,0.1,0.5c0.8,1.6,1.2,3.1,1.2,3.4c0,0.4-0.3,1-1,1 c-0.6,0-0.7,0-1.2-1.3c-1.2-2.9-2.9-4.7-3.8-4.7c-0.6,0-1.1,0.5-1.1,1.1c0,0.3,0.1,0.7,0.4,0.9c3.2,2.6,2,6.2,5.7,6.2 c2.1,0,3.3-1.6,3.3-3.2c0-0.6-0.2-1.7-0.7-2.8h4.7c1.7,0,3.1-1.4,3.1-3.2C24,12.3,23.4,11.3,22.6,10.7z"/>
18
+ <title id="altIconTitle">UNLIKE</title>
17
19
  </svg>
18
20
  </button>
19
21
  </div>
@@ -1,22 +1,16 @@
1
1
  import { ComponentFixture, TestBed } from '@angular/core/testing';
2
- import { By } from '@angular/platform-browser';
3
- import { LoggerInstance } from 'src/chat21-core/providers/logger/loggerInstance';
4
- import { CustomLogger } from 'src/chat21-core/providers/logger/customLogger';
5
- import { NGXLogger } from 'ngx-logger';
6
2
 
7
3
  import { LikeUnlikeComponent } from './like-unlike.component';
8
4
 
9
5
  describe('LikeUnlikeComponent', () => {
10
6
  let component: LikeUnlikeComponent;
11
7
  let fixture: ComponentFixture<LikeUnlikeComponent>;
12
- const ngxlogger = jasmine.createSpyObj('NGXLogger', ['log', 'trace', 'debug', 'warn', 'error', 'info']);
13
- const customLogger = new CustomLogger(ngxlogger);
14
8
 
15
9
  beforeEach(async () => {
16
- LoggerInstance.setInstance(customLogger);
17
10
  await TestBed.configureTestingModule({
18
- declarations: [LikeUnlikeComponent],
19
- }).compileComponents();
11
+ declarations: [ LikeUnlikeComponent ]
12
+ })
13
+ .compileComponents();
20
14
  });
21
15
 
22
16
  beforeEach(() => {
@@ -28,26 +22,4 @@ describe('LikeUnlikeComponent', () => {
28
22
  it('should create', () => {
29
23
  expect(component).toBeTruthy();
30
24
  });
31
-
32
- it('onClick should log icon id', () => {
33
- spyOn((component as any).logger, 'debug');
34
- component.onClick('like');
35
- expect((component as any).logger.debug).toHaveBeenCalledWith('[LIKE-UNLIKE] onClick-->', 'like');
36
- });
37
-
38
- it('like button should have accessible name', () => {
39
- const btn = fixture.debugElement.queryAll(By.css('button'))[0];
40
- expect(btn.nativeElement.getAttribute('aria-label')).toBe('Like message');
41
- });
42
-
43
- it('unlike button should have accessible name', () => {
44
- const btn = fixture.debugElement.queryAll(By.css('button'))[1];
45
- expect(btn.nativeElement.getAttribute('aria-label')).toBe('Unlike message');
46
- });
47
-
48
- it('clicking like should invoke logger', () => {
49
- spyOn((component as any).logger, 'debug');
50
- fixture.debugElement.queryAll(By.css('button'))[0].triggerEventHandler('click', {});
51
- expect((component as any).logger.debug).toHaveBeenCalledWith('[LIKE-UNLIKE] onClick-->', 'like');
52
- });
53
25
  });
@@ -1,10 +1,6 @@
1
- import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
1
+ import { async, ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
2
2
  import { By } from '@angular/platform-browser';
3
- import {
4
- MSG_STATUS_RETURN_RECEIPT,
5
- MSG_STATUS_SENT,
6
- MSG_STATUS_SENT_SERVER,
7
- } from 'src/app/utils/constants';
3
+ import { MSG_STATUS_SENT } from 'src/chat21-core/utils/constants';
8
4
 
9
5
  import { ReturnReceiptComponent } from './return-receipt.component';
10
6
 
@@ -14,48 +10,31 @@ describe('ReturnReceiptComponent', () => {
14
10
 
15
11
  beforeEach(waitForAsync(() => {
16
12
  TestBed.configureTestingModule({
17
- declarations: [ReturnReceiptComponent],
18
- }).compileComponents();
13
+ declarations: [ ReturnReceiptComponent ]
14
+ })
15
+ .compileComponents();
19
16
  }));
20
17
 
21
18
  beforeEach(() => {
22
19
  fixture = TestBed.createComponent(ReturnReceiptComponent);
23
20
  component = fixture.componentInstance;
21
+ fixture.detectChanges();
24
22
  });
25
23
 
26
24
  it('should create', () => {
27
- fixture.detectChanges();
28
25
  expect(component).toBeTruthy();
29
26
  });
30
27
 
31
- it('should render schedule icon when status is falsy', () => {
32
- component.status = 0 as any;
33
- fixture.detectChanges();
34
- const icons = fixture.debugElement.queryAll(By.css('.icon'));
35
- expect(icons.length).toBe(1);
36
- });
37
-
38
- it('should render sent icon for MSG_STATUS_SENT', () => {
39
- component.status = MSG_STATUS_SENT;
40
- fixture.detectChanges();
41
- expect(fixture.debugElement.queryAll(By.css('.icon')).length).toBe(1);
42
- });
43
-
44
- it('should render server-sent icon for MSG_STATUS_SENT_SERVER', () => {
45
- component.status = MSG_STATUS_SENT_SERVER;
46
- fixture.detectChanges();
47
- expect(fixture.debugElement.queryAll(By.css('.icon')).length).toBe(1);
48
- });
49
-
50
- it('should render return receipt icon for MSG_STATUS_RETURN_RECEIPT', () => {
51
- component.status = MSG_STATUS_RETURN_RECEIPT;
28
+ it('shold render MSG_STATUS_SENT icon', ()=> {
29
+ component.status= MSG_STATUS_SENT
52
30
  fixture.detectChanges();
53
- expect(fixture.debugElement.queryAll(By.css('.icon')).length).toBe(1);
54
- });
55
-
56
- it('should expose status constants on component', () => {
57
- expect(component.MSG_STATUS_SENT).toBe(MSG_STATUS_SENT);
58
- expect(component.MSG_STATUS_SENT_SERVER).toBe(MSG_STATUS_SENT_SERVER);
59
- expect(component.MSG_STATUS_RETURN_RECEIPT).toBe(MSG_STATUS_RETURN_RECEIPT);
60
- });
31
+ expect(component.status).toBe(MSG_STATUS_SENT)
32
+ })
33
+
34
+ // it('shold render MSG_STATUS_SENT icon', ()=> {
35
+ // component.status= MSG_STATUS_SENT
36
+ // fixture.detectChanges();
37
+ // let element = fixture.debugElement.query(By.css('icon'))
38
+ // expect(element.classes).toBeE('icon')
39
+ // })
61
40
  });
@@ -1,3 +1,3 @@
1
- <div #messageEl class="message_innerhtml marked"
2
- [innerHTML]="printMessage(text, messageEl, this) | marked"
3
- [style.color]="color"></div>
1
+ <p #messageEl class="message_innerhtml marked"
2
+ [innerHTML]="printMessage(text, messageEl, this) | marked"
3
+ [style.color]="color"></p>