@chat21/chat21-web-widget 5.1.32-rc3 → 5.1.33

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 (59) 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 +6 -41
  4. package/Dockerfile +5 -4
  5. package/angular.json +2 -5
  6. package/deploy_amazon_beta.sh +7 -17
  7. package/deploy_amazon_prod.sh +2 -2
  8. package/docs/changelog/this-branch.md +0 -36
  9. package/nginx.conf +2 -22
  10. package/package.json +1 -4
  11. package/src/app/app.component.ts +9 -10
  12. package/src/app/app.module.ts +0 -9
  13. package/src/app/component/conversation-detail/conversation/conversation.component.html +1 -6
  14. package/src/app/component/conversation-detail/conversation/conversation.component.scss +2 -2
  15. package/src/app/component/conversation-detail/conversation/conversation.component.ts +5 -34
  16. package/src/app/component/conversation-detail/conversation-content/conversation-content.component.html +1 -1
  17. package/src/app/component/conversation-detail/conversation-content/conversation-content.component.scss +1 -1
  18. package/src/app/component/conversation-detail/conversation-content/conversation-content.component.ts +0 -1
  19. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.html +79 -146
  20. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.scss +13 -131
  21. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.ts +7 -108
  22. package/src/app/component/last-message/last-message.component.ts +1 -4
  23. package/src/app/component/message/audio/audio.component.ts +5 -0
  24. package/src/app/component/message/bubble-message/bubble-message.component.html +1 -6
  25. package/src/app/component/message/bubble-message/bubble-message.component.ts +1 -2
  26. package/src/app/providers/global-settings.service.ts +0 -21
  27. package/src/app/providers/translator.service.ts +0 -2
  28. package/src/app/sass/_variables.scss +0 -1
  29. package/src/app/utils/globals.ts +1 -7
  30. package/src/assets/i18n/en.json +0 -1
  31. package/src/assets/i18n/es.json +0 -1
  32. package/src/assets/i18n/fr.json +0 -1
  33. package/src/assets/i18n/it.json +0 -1
  34. package/src/chat21-core/models/message.ts +1 -2
  35. package/src/chat21-core/providers/firebase/firebase-conversation-handler.ts +2 -3
  36. package/src/chat21-core/providers/mqtt/mqtt-conversation-handler.ts +0 -12
  37. package/src/chat21-core/providers/tiledesk/tiledesk-requests.service.ts +1 -1
  38. package/src/chat21-core/utils/utils-message.ts +0 -7
  39. package/src/chat21-core/utils/utils.ts +2 -5
  40. package/src/launch.js +41 -32
  41. package/src/launch_template.js +41 -32
  42. package/tsconfig.json +0 -5
  43. package/src/app/component/message/audio-sync/audio-sync.component.html +0 -19
  44. package/src/app/component/message/audio-sync/audio-sync.component.scss +0 -65
  45. package/src/app/component/message/audio-sync/audio-sync.component.spec.ts +0 -23
  46. package/src/app/component/message/audio-sync/audio-sync.component.ts +0 -197
  47. package/src/app/providers/voice/STT&TTS/openai-voice.config.ts +0 -12
  48. package/src/app/providers/voice/STT&TTS/openai-voice.provider.ts +0 -171
  49. package/src/app/providers/voice/STT&TTS/speech-provider.abstract.ts +0 -39
  50. package/src/app/providers/voice/audio.types.ts +0 -34
  51. package/src/app/providers/voice/vad.service.spec.ts +0 -28
  52. package/src/app/providers/voice/vad.service.ts +0 -70
  53. package/src/app/providers/voice/voice.service.spec.ts +0 -60
  54. package/src/app/providers/voice/voice.service.ts +0 -264
  55. package/src/app/shims/onnxruntime-web-wasm.ts +0 -4
  56. package/src/assets/onnx/ort-wasm-simd-threaded.mjs +0 -59
  57. package/src/assets/onnx/ort-wasm-simd-threaded.wasm +0 -0
  58. package/src/assets/vad/silero_vad_legacy.onnx +0 -0
  59. package/src/assets/vad/vad.worklet.bundle.min.js +0 -1
@@ -154,10 +154,15 @@ export class AudioComponent implements AfterViewInit {
154
154
  // });
155
155
 
156
156
  const response = await fetch(this.rawAudioUrl!);
157
+ this.logger.debug('getAudioDuration: response ---> ', response)
157
158
  const arrayBuffer = await response.arrayBuffer();
159
+ this.logger.debug('getAudioDuration: arrayBuffer ---> ', arrayBuffer)
158
160
  const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)();
161
+ this.logger.debug('getAudioDuration: audioContext ---> ', audioContext)
159
162
  const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
163
+ this.logger.debug('getAudioDuration: audioBuffer ---> ', audioBuffer)
160
164
  this.audioDuration = audioBuffer.duration;
165
+ this.logger.debug('getAudioDuration: audioDuration ---> ', this.audioDuration)
161
166
 
162
167
  }
163
168
 
@@ -64,11 +64,6 @@
64
64
  [stylesMap]="stylesMap">
65
65
  </chat-audio>
66
66
 
67
- <chat-audio-sync *ngIf="isAudioTTS(message)"
68
- [message]="message"
69
- [color]="fontColor">
70
- </chat-audio-sync>
71
-
72
67
 
73
68
  <!-- <chat-frame *ngIf="message.metadata && message.metadata.type && message.metadata.type.includes('video')"
74
69
  [metadata]="message.metadata"
@@ -80,7 +75,7 @@
80
75
  <!-- <div *ngIf="message.type == 'text'"> -->
81
76
 
82
77
  <!-- tooltip="{{message.timestamp | dateAgo}} ({{message.timestamp | date:'shortDate'}} {{message.timestamp | date:'HH:mm:ss'}})" placement="bottom" -->
83
- <div *ngIf="message?.text && (!isAudio(message) && !isAudioTTS(message))" >
78
+ <div *ngIf="message?.text && !isAudio(message)" >
84
79
 
85
80
  <!-- [htmlEnabled]="(message?.type==='html')? true : false" -->
86
81
  <chat-text *ngIf="message?.type !=='html'"
@@ -5,7 +5,7 @@ import { LoggerService } from 'src/chat21-core/providers/abstract/logger.service
5
5
  import { LoggerInstance } from 'src/chat21-core/providers/logger/loggerInstance';
6
6
  import { MAX_WIDTH_IMAGES, MESSAGE_TYPE_MINE, MESSAGE_TYPE_OTHERS, MIN_WIDTH_IMAGES } from 'src/chat21-core/utils/constants';
7
7
  import { convertColorToRGBA } from 'src/chat21-core/utils/utils';
8
- import { isAudio, isAudioTTS, isFile, isFrame, isImage, messageType } from 'src/chat21-core/utils/utils-message';
8
+ import { isAudio, isFile, isFrame, isImage, messageType } from 'src/chat21-core/utils/utils-message';
9
9
  import { getColorBck } from 'src/chat21-core/utils/utils-user';
10
10
 
11
11
  @Component({
@@ -26,7 +26,6 @@ export class BubbleMessageComponent implements OnInit {
26
26
  isFile = isFile;
27
27
  isFrame = isFrame;
28
28
  isAudio = isAudio;
29
- isAudioTTS=isAudioTTS;
30
29
  convertColorToRGBA = convertColorToRGBA
31
30
 
32
31
  // ========== begin:: check message type functions ======= //
@@ -1125,22 +1125,11 @@ export class GlobalSettingsService {
1125
1125
  if (TEMP !== undefined) {
1126
1126
  globals.showAudioRecorderFooterButton = (TEMP === true) ? true : false;
1127
1127
  }
1128
- TEMP = tiledeskSettings['showAudioStreamFooterButton'];
1129
- // this.logger.debug('[GLOBAL-SET] setVariablesFromSettings > showAudioStreamFooterButton:: ', TEMP]);
1130
- if (TEMP !== undefined) {
1131
- globals.showAudioStreamFooterButton = (TEMP === true) ? true : false;
1132
- }
1133
1128
  TEMP = tiledeskSettings['size'];
1134
1129
  // this.logger.debug('[GLOBAL-SET] setVariablesFromSettings > size:: ', TEMP]);
1135
1130
  if (TEMP !== undefined) {
1136
1131
  globals.size = TEMP;
1137
1132
  }
1138
-
1139
- TEMP = tiledeskSettings['closeChatInConversation'];
1140
- // this.logger.debug('[GLOBAL-SET] setVariablesFromSettings > closeChatInConversation:: ', TEMP]);
1141
- if (TEMP !== undefined) {
1142
- globals.closeChatInConversation = (TEMP === true) ? true : false;
1143
- }
1144
1133
  }
1145
1134
 
1146
1135
  /**
@@ -1878,11 +1867,6 @@ export class GlobalSettingsService {
1878
1867
  globals.showAttachmentFooterButton = stringToBoolean(TEMP);
1879
1868
  }
1880
1869
 
1881
- TEMP = getParameterByName(windowContext, 'tiledesk_showAudioStreamFooterButton');
1882
- if (TEMP) {
1883
- globals.showAudioStreamFooterButton = stringToBoolean(TEMP);
1884
- }
1885
-
1886
1870
  TEMP = getParameterByName(windowContext, 'tiledesk_showEmojiFooterButton');
1887
1871
  if (TEMP) {
1888
1872
  globals.showEmojiFooterButton = stringToBoolean(TEMP);
@@ -1892,11 +1876,6 @@ export class GlobalSettingsService {
1892
1876
  if (TEMP) {
1893
1877
  globals.size = TEMP;
1894
1878
  }
1895
-
1896
- TEMP = getParameterByName(windowContext, 'tiledesk_closeChatInConversation');
1897
- if (TEMP) {
1898
- globals.closeChatInConversation = stringToBoolean(TEMP);
1899
- }
1900
1879
 
1901
1880
  }
1902
1881
 
@@ -302,7 +302,6 @@ export class TranslatorService {
302
302
  'CLOSED',
303
303
  'LABEL_PREVIEW',
304
304
  'MAX_ATTACHMENT',
305
- 'MAX_ATTACHMENT_ERROR',
306
305
  'EMOJI'
307
306
  ];
308
307
 
@@ -359,7 +358,6 @@ export class TranslatorService {
359
358
  globals.LABEL_PREVIEW = res['LABEL_PREVIEW']
360
359
  globals.LABEL_ERROR_FIELD_REQUIRED= res['LABEL_ERROR_FIELD_REQUIRED']
361
360
  globals.MAX_ATTACHMENT = res['MAX_ATTACHMENT']
362
- globals.MAX_ATTACHMENT_ERROR = res['MAX_ATTACHMENT_ERROR']
363
361
  globals.EMOJI = res['EMOJI']
364
362
 
365
363
 
@@ -36,7 +36,6 @@
36
36
 
37
37
  --chat-footer-height: 64px;
38
38
  --chat-footer-logo-height: 30px;
39
- --chat-footer-close-button-height: 30px;
40
39
  --chat-footer-border-radius: 16px;
41
40
  --chat-footer-background-color: #f6f7fb;
42
41
  --chat-footer-color: #1a1a1a;
@@ -219,7 +219,6 @@ export class Globals {
219
219
  showEmojiFooterButton: boolean // ******* new ********
220
220
  showAttachmentFooterButton: boolean // ******* new ********
221
221
  showAudioRecorderFooterButton: boolean // ******* new ********
222
- showAudioStreamFooterButton: boolean // ******* new ********
223
222
 
224
223
  allowedOnSpecificUrl: boolean // ******* new ********
225
224
  allowedOnSpecificUrlList: Array<string> // ******* new ********
@@ -228,8 +227,6 @@ export class Globals {
228
227
  fontFamilySource: string; // ******* new ********
229
228
 
230
229
  size: 'min' | 'max' | 'top'; // ******* new ********
231
-
232
- closeChatInConversation: boolean; // ******* new ********
233
230
  constructor(
234
231
  ) { }
235
232
 
@@ -438,8 +435,6 @@ export class Globals {
438
435
  this.showAttachmentFooterButton = true;
439
436
  /** show/hide rec audio option in footer chat-detail page */
440
437
  this.showAudioRecorderFooterButton = true;
441
- /** show/hide stream audio option in footer chat-detail page */
442
- this.showAudioStreamFooterButton = true;
443
438
  /** enabled to set a list of pattern url able to load the widget **/
444
439
  this.allowedOnSpecificUrl = false
445
440
  /** set a list of pattern url able to load the widget */
@@ -448,8 +443,7 @@ export class Globals {
448
443
  this.hasCalloutInWidgetConfig = false;
449
444
  /** set widget size from 3 different positions: min, max, top */
450
445
  this.size = 'min';
451
- /** enable to close the chat in conversation */
452
- this.closeChatInConversation = false;
446
+
453
447
  // ============ END: SET EXTERNAL PARAMETERS ==============//
454
448
 
455
449
 
@@ -97,6 +97,5 @@
97
97
  "EMOJI_NOT_ELLOWED":"Emoji not allowed",
98
98
  "DOMAIN_NOT_ALLOWED":"URL contains a non-allowed domain",
99
99
  "MAX_ATTACHMENT": "Max allowed size {{FILE_SIZE_LIMIT}}Mb",
100
- "MAX_ATTACHMENT_ERROR": "The file exceeds the maximum allowed size",
101
100
  "EMOJI": "Emoji"
102
101
  }
@@ -97,6 +97,5 @@
97
97
  "EMOJI_NOT_ELLOWED":"Emoji no permitido",
98
98
  "DOMAIN_NOT_ALLOWED":"La URL contiene un dominio no permitido",
99
99
  "MAX_ATTACHMENT": "Tamaño máximo permitido {{FILE_SIZE_LIMIT}}Mb",
100
- "MAX_ATTACHMENT_ERROR": "El archivo supera el tamaño máximo permitido",
101
100
  "EMOJI": "Emoji"
102
101
  }
@@ -97,6 +97,5 @@
97
97
  "EMOJI_NOT_ELLOWED":"Emoji non autorisé",
98
98
  "DOMAIN_NOT_ALLOWED":"L'URL contient un domaine non autorisé",
99
99
  "MAX_ATTACHMENT": "Taille maximale autorisée {{FILE_SIZE_LIMIT}}Mo",
100
- "MAX_ATTACHMENT_ERROR": "Le fichier dépasse la taille maximale autorisée",
101
100
  "EMOJI": "Emoji"
102
101
  }
@@ -95,6 +95,5 @@
95
95
  "EMOJI_NOT_ELLOWED":"Emoji non consentiti",
96
96
  "DOMAIN_NOT_ALLOWED":"L'URL contiene un dominio non consentito",
97
97
  "MAX_ATTACHMENT": "Dimensione massima consentita {{FILE_SIZE_LIMIT}}Mb",
98
- "MAX_ATTACHMENT_ERROR": "Il file supera la dimensione massima consentita",
99
98
  "EMOJI": "Emoji"
100
99
  }
@@ -14,7 +14,6 @@ export class MessageModel {
14
14
  public attributes: any,
15
15
  public channel_type: string,
16
16
  public isSender: boolean,
17
- public emoticon?: boolean,
18
- public isJustRecived?: boolean
17
+ public emoticon?: boolean
19
18
  ) { }
20
19
  }
@@ -253,7 +253,9 @@ export class FirebaseConversationHandler extends ConversationHandlerService {
253
253
  }
254
254
  }
255
255
 
256
+
256
257
 
258
+
257
259
  this.addRepalceMessageInArray(msg.uid, msg);
258
260
  this.messageAdded.next(msg);
259
261
  } else {
@@ -492,9 +494,6 @@ export class FirebaseConversationHandler extends ConversationHandlerService {
492
494
  commands[i+1]? commands[i+1].time = 0 : null
493
495
  }
494
496
  }
495
-
496
- command.message.isJustRecived = isJustRecived( that.startTime.getTime(), msg.timestamp );
497
-
498
497
  that.generateMessageObject(msg, command.message, function () {
499
498
  i += 1
500
499
  if (i < commands.length) {
@@ -273,16 +273,6 @@ export class MQTTConversationHandler extends ConversationHandlerService {
273
273
  if(isInfoMessage){
274
274
  this.messageInfo.next(msg)
275
275
  }
276
-
277
-
278
-
279
-
280
-
281
-
282
-
283
-
284
-
285
-
286
276
 
287
277
  if(isInfoMessage && hideInfoMessage(msg, this.showInfoMessage)){
288
278
  //if showBubbleInfoMessage array keys not includes msg.attributes.messagelabel['key'] exclude CURRENT INFO MESSAGE
@@ -502,8 +492,6 @@ export class MQTTConversationHandler extends ConversationHandlerService {
502
492
  }
503
493
  }
504
494
 
505
- command.message.isJustRecived = isJustRecived( that.startTime.getTime(), msg.timestamp );
506
-
507
495
  that.generateMessageObject(msg, command.message, i, function () {
508
496
  i += 1
509
497
  if (i < commands.length) {
@@ -71,7 +71,7 @@ export class TiledeskRequestsService {
71
71
 
72
72
  public getMyRequests(): Promise<{ requests: Array<any>}> {
73
73
  this.tiledeskToken = this.appStorage.getItem('tiledeskToken')
74
- const url = this.URL_TILEDESK_REQUEST + 'me?preflight=true'
74
+ const url = this.URL_TILEDESK_REQUEST + '/me?preflight=true'
75
75
  this.logger.log('[TILEDESK-SERVICE] - GET REQUEST url ', url);
76
76
  const httpOptions = {
77
77
  headers: new HttpHeaders({
@@ -48,13 +48,6 @@ export function isAudio(message: any) {
48
48
  return false;
49
49
  }
50
50
 
51
- export function isAudioTTS(message: any) {
52
- if (message && message.type && message.type === 'tts' && message.metadata && message.metadata.src && message.metadata.type.includes('audio') ) {
53
- return true;
54
- }
55
- return false;
56
- }
57
-
58
51
  /** */
59
52
  export function isInfo(message: any) {
60
53
  if (message && message.attributes && (message.attributes.subtype === 'info' || message.attributes.subtype === 'info/support')) {
@@ -773,11 +773,6 @@ export function isAllowedUrlInText(text: string, allowedUrls: string[]) {
773
773
  return nonWhitelistedDomains.length === 0;
774
774
  }
775
775
 
776
- // function extractUrls(text: string): string[] {
777
- // const urlRegex = /https?:\/\/[^\s]+/g;
778
- // return text.match(urlRegex) || [];
779
- // }
780
-
781
776
  function extractUrls(text: string): string[] {
782
777
  // Rileva URL con o senza protocollo (http/https)
783
778
  const urlRegex = /\b((https?:\/\/)?(www\.)?[a-z0-9.-]+\.[a-z]{2,})(\/[^\s]*)?/gi;
@@ -792,3 +787,5 @@ function extractUrls(text: string): string[] {
792
787
  }
793
788
 
794
789
 
790
+
791
+
package/src/launch.js CHANGED
@@ -218,67 +218,76 @@ function loadIframe(tiledeskScriptBaseLocation) {
218
218
  iDiv.appendChild(ifrm);
219
219
 
220
220
  // Funzione helper per caricare iframe con fallback per compatibilità CSP (Wix, etc.)
221
- // Usa Blob URL come metodo principale (più compatibile con CSP) con fallback a srcdoc e document.write
222
- function loadIframeContent(iframe, htmlContent, baseLocation) {
223
- var isLocalhost = baseLocation.includes('localhost');
221
+ // Priorità: document.write / srcdoc prima della Blob URL. Le Blob URL spesso danno origine opaca
222
+ // (blob:null): l'iframe non può leggere window.parent.tiledeskSettings → projectid mancante.
223
+ function loadIframeContent(iframe, htmlContent) {
224
224
  var blobUrl = null;
225
-
226
- // Metodo 1: Blob URL (più compatibile con CSP di Wix e altre piattaforme)
227
- // Usa Blob URL come metodo principale perché è meno spesso bloccato da CSP rispetto a srcdoc
225
+
226
+ // 1) document.write: iframe stessa origine della pagina host tiledeskSettings sul parent accessibile
227
+ try {
228
+ var cw = iframe.contentWindow;
229
+ if (cw && cw.document) {
230
+ cw.document.open();
231
+ cw.document.write(htmlContent);
232
+ cw.document.close();
233
+ return;
234
+ }
235
+ } catch (e) {
236
+ console.warn('[Tiledesk] iframe document.write failed, trying srcdoc/blob:', e);
237
+ }
238
+
239
+ // 2) srcdoc: stessa origine del parent (HTML5); utile se document.write è bloccato
240
+ if ('srcdoc' in iframe) {
241
+ try {
242
+ iframe.srcdoc = htmlContent;
243
+ return;
244
+ } catch (e) {
245
+ console.warn('[Tiledesk] iframe srcdoc failed, trying blob:', e);
246
+ }
247
+ }
248
+
249
+ // 3) Blob URL (spesso permesso da CSP dove srcdoc/write no; può rompere lettura parent.tiledeskSettings)
228
250
  if (typeof Blob !== 'undefined' && typeof URL !== 'undefined' && URL.createObjectURL) {
229
251
  try {
230
252
  var blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' });
231
253
  blobUrl = URL.createObjectURL(blob);
232
254
  iframe.src = blobUrl;
233
-
234
- // Cleanup del blob URL dopo il caricamento per liberare memoria
255
+
235
256
  var originalOnload = iframe.onload;
236
257
  iframe.onload = function() {
237
- // Revoca il blob URL dopo un delay per assicurarsi che tutto sia caricato
238
258
  setTimeout(function() {
239
259
  if (blobUrl) {
240
260
  try {
241
261
  URL.revokeObjectURL(blobUrl);
242
262
  blobUrl = null;
243
- } catch(e) {
244
- console.warn('Error revoking blob URL:', e);
263
+ } catch (err) {
264
+ console.warn('Error revoking blob URL:', err);
245
265
  }
246
266
  }
247
267
  }, 1000);
248
268
  if (originalOnload) originalOnload.call(this);
249
269
  };
250
- return; // Blob URL impostato con successo
251
- } catch(e) {
252
- console.warn('Blob URL not available, trying srcdoc:', e);
270
+ return;
271
+ } catch (e) {
272
+ console.warn('Blob URL not available:', e);
253
273
  }
254
274
  }
255
-
256
- // Metodo 2: srcdoc (fallback se Blob URL non disponibile)
257
- // Skip per localhost (usa document.write per compatibilità sviluppo)
258
- if (!isLocalhost && 'srcdoc' in iframe) {
259
- try {
260
- iframe.srcdoc = htmlContent;
261
- return; // srcdoc impostato
262
- } catch(e) {
263
- console.warn('srcdoc not allowed, trying document.write:', e);
264
- }
265
- }
266
-
267
- // Metodo 3: document.write (fallback finale, funziona su localhost e browser vecchi)
268
- if (isLocalhost || (iframe.contentWindow && iframe.contentWindow.document)) {
275
+
276
+ // 4) Ultimo tentativo document.write (iframe magari non pronto al primo passo)
277
+ if (iframe.contentWindow && iframe.contentWindow.document) {
269
278
  try {
270
279
  iframe.contentWindow.document.open();
271
280
  iframe.contentWindow.document.write(htmlContent);
272
281
  iframe.contentWindow.document.close();
273
- return; // document.write completato
274
- } catch(e) {
275
- console.error('All iframe loading methods failed:', e);
282
+ return;
283
+ } catch (e) {
284
+ console.error('[Tiledesk] All iframe loading methods failed:', e);
276
285
  }
277
286
  }
278
287
  }
279
288
 
280
289
  // Carica il contenuto dell'iframe con fallback automatico
281
- loadIframeContent(ifrm, srcTileDesk, tiledeskScriptBaseLocation);
290
+ loadIframeContent(ifrm, srcTileDesk);
282
291
 
283
292
 
284
293
  }
@@ -219,67 +219,76 @@ function loadIframe(tiledeskScriptBaseLocation) {
219
219
  iDiv.appendChild(ifrm);
220
220
 
221
221
  // Funzione helper per caricare iframe con fallback per compatibilità CSP (Wix, etc.)
222
- // Usa Blob URL come metodo principale (più compatibile con CSP) con fallback a srcdoc e document.write
223
- function loadIframeContent(iframe, htmlContent, baseLocation) {
224
- var isLocalhost = baseLocation.includes('localhost');
222
+ // Priorità: document.write / srcdoc prima della Blob URL. Le Blob URL spesso danno origine opaca
223
+ // (blob:null): l'iframe non può leggere window.parent.tiledeskSettings → projectid mancante.
224
+ function loadIframeContent(iframe, htmlContent) {
225
225
  var blobUrl = null;
226
-
227
- // Metodo 1: Blob URL (più compatibile con CSP di Wix e altre piattaforme)
228
- // Usa Blob URL come metodo principale perché è meno spesso bloccato da CSP rispetto a srcdoc
226
+
227
+ // 1) document.write: iframe stessa origine della pagina host tiledeskSettings sul parent accessibile
228
+ try {
229
+ var cw = iframe.contentWindow;
230
+ if (cw && cw.document) {
231
+ cw.document.open();
232
+ cw.document.write(htmlContent);
233
+ cw.document.close();
234
+ return;
235
+ }
236
+ } catch (e) {
237
+ console.warn('[Tiledesk] iframe document.write failed, trying srcdoc/blob:', e);
238
+ }
239
+
240
+ // 2) srcdoc: stessa origine del parent (HTML5); utile se document.write è bloccato
241
+ if ('srcdoc' in iframe) {
242
+ try {
243
+ iframe.srcdoc = htmlContent;
244
+ return;
245
+ } catch (e) {
246
+ console.warn('[Tiledesk] iframe srcdoc failed, trying blob:', e);
247
+ }
248
+ }
249
+
250
+ // 3) Blob URL (spesso permesso da CSP dove srcdoc/write no; può rompere lettura parent.tiledeskSettings)
229
251
  if (typeof Blob !== 'undefined' && typeof URL !== 'undefined' && URL.createObjectURL) {
230
252
  try {
231
253
  var blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' });
232
254
  blobUrl = URL.createObjectURL(blob);
233
255
  iframe.src = blobUrl;
234
-
235
- // Cleanup del blob URL dopo il caricamento per liberare memoria
256
+
236
257
  var originalOnload = iframe.onload;
237
258
  iframe.onload = function() {
238
- // Revoca il blob URL dopo un delay per assicurarsi che tutto sia caricato
239
259
  setTimeout(function() {
240
260
  if (blobUrl) {
241
261
  try {
242
262
  URL.revokeObjectURL(blobUrl);
243
263
  blobUrl = null;
244
- } catch(e) {
245
- console.warn('Error revoking blob URL:', e);
264
+ } catch (err) {
265
+ console.warn('Error revoking blob URL:', err);
246
266
  }
247
267
  }
248
268
  }, 1000);
249
269
  if (originalOnload) originalOnload.call(this);
250
270
  };
251
- return; // Blob URL impostato con successo
252
- } catch(e) {
253
- console.warn('Blob URL not available, trying srcdoc:', e);
254
- }
255
- }
256
-
257
- // Metodo 2: srcdoc (fallback se Blob URL non disponibile)
258
- // Skip per localhost (usa document.write per compatibilità sviluppo)
259
- if (!isLocalhost && 'srcdoc' in iframe) {
260
- try {
261
- iframe.srcdoc = htmlContent;
262
- return; // srcdoc impostato
263
- } catch(e) {
264
- console.warn('srcdoc not allowed, trying document.write:', e);
271
+ return;
272
+ } catch (e) {
273
+ console.warn('Blob URL not available:', e);
265
274
  }
266
275
  }
267
-
268
- // Metodo 3: document.write (fallback finale, funziona su localhost e browser vecchi)
269
- if (isLocalhost || (iframe.contentWindow && iframe.contentWindow.document)) {
276
+
277
+ // 4) Ultimo tentativo document.write (iframe magari non pronto al primo passo)
278
+ if (iframe.contentWindow && iframe.contentWindow.document) {
270
279
  try {
271
280
  iframe.contentWindow.document.open();
272
281
  iframe.contentWindow.document.write(htmlContent);
273
282
  iframe.contentWindow.document.close();
274
- return; // document.write completato
275
- } catch(e) {
276
- console.error('All iframe loading methods failed:', e);
283
+ return;
284
+ } catch (e) {
285
+ console.error('[Tiledesk] All iframe loading methods failed:', e);
277
286
  }
278
287
  }
279
288
  }
280
289
 
281
290
  // Carica il contenuto dell'iframe con fallback automatico
282
- loadIframeContent(ifrm, srcTileDesk, tiledeskScriptBaseLocation);
291
+ loadIframeContent(ifrm, srcTileDesk);
283
292
 
284
293
 
285
294
  }
package/tsconfig.json CHANGED
@@ -23,11 +23,6 @@
23
23
  "dom"
24
24
  ],
25
25
  "resolveJsonModule": true,
26
- "paths": {
27
- "onnxruntime-web/wasm": [
28
- "src/app/shims/onnxruntime-web-wasm.ts"
29
- ]
30
- }
31
26
  },
32
27
  "skipLibCheck": true,
33
28
  "angularCompilerOptions": {
@@ -1,19 +0,0 @@
1
- <div class="lyrics-container">
2
-
3
- <audio
4
- #audioPlayer
5
- [src]="message?.metadata?.src"
6
- (timeupdate)="onTimeUpdate()"
7
- style="display:none">
8
- </audio>
9
-
10
- <p class="lyrics message_innerhtml marked" #transcriptBox [style.color]="color">
11
- <span
12
- *ngFor="let w of words; let i = index; trackBy: trackByIndex"
13
- class="word"
14
- [ngClass]="w.state">
15
- {{ w.text }}
16
- </span>
17
- </p>
18
-
19
- </div>
@@ -1,65 +0,0 @@
1
- :host {
2
- display: block;
3
- font-size: var(--font-size-bubble-message, 14px);
4
- }
5
-
6
- /* Allineato a text.component.scss (.message_innerhtml, p) */
7
- .message_innerhtml {
8
- margin: 0;
9
-
10
- &.marked {
11
- padding: 12px 16px;
12
- margin-block-start: 0em !important;
13
- margin-block-end: 0em !important;
14
- }
15
- }
16
-
17
- .lyrics {
18
- font-size: inherit;
19
- margin: 0;
20
- line-height: 1.4em;
21
- font-style: normal;
22
- letter-spacing: normal;
23
- font-stretch: normal;
24
- font-variant: normal;
25
- font-weight: 300;
26
- overflow: hidden;
27
-
28
- display: flex;
29
- flex-wrap: wrap;
30
- gap: 6px;
31
- /* Colore bubble: da [style.color] / @Input() color — ereditato dalle .word */
32
- }
33
-
34
- /* base word */
35
- .word {
36
- transition:
37
- transform 0.3s cubic-bezier(0.2, 0.8, 0.2, 1),
38
- color 0.3s ease,
39
- opacity 0.3s ease,
40
- filter 0.3s ease;
41
-
42
- will-change: transform;
43
- }
44
-
45
- /* FUTURE */
46
- .word.future {
47
- opacity: 0;
48
- transform: scale(0.98);
49
- }
50
-
51
- /* PAST: stesso colore del testo bubble (@Input color sul <p>) */
52
- .word.past {
53
- opacity: 1;
54
- color: inherit;
55
- transform: scale(1);
56
- }
57
-
58
- /* ACTIVE (solo momentaneo, tipo “karaoke flash”) */
59
- .word.active {
60
- opacity: 1;
61
- color: #00c3ff;
62
- font-weight: 700;
63
- transform: scale(1.18);
64
- text-shadow: 0 0 10px rgba(0, 195, 255, 0.35);
65
- }
@@ -1,23 +0,0 @@
1
- import { ComponentFixture, TestBed } from '@angular/core/testing';
2
-
3
- import { AudioSyncComponent } from './audio-sync.component';
4
-
5
- describe('AudioSyncComponent', () => {
6
- let component: AudioSyncComponent;
7
- let fixture: ComponentFixture<AudioSyncComponent>;
8
-
9
- beforeEach(async () => {
10
- await TestBed.configureTestingModule({
11
- imports: [AudioSyncComponent]
12
- })
13
- .compileComponents();
14
-
15
- fixture = TestBed.createComponent(AudioSyncComponent);
16
- component = fixture.componentInstance;
17
- fixture.detectChanges();
18
- });
19
-
20
- it('should create', () => {
21
- expect(component).toBeTruthy();
22
- });
23
- });