@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.
- package/.github/workflows/docker-community-push-latest.yml +13 -23
- package/.github/workflows/docker-image-tag-community-tag-push.yml +12 -22
- package/CHANGELOG.md +6 -41
- package/Dockerfile +5 -4
- package/angular.json +2 -5
- package/deploy_amazon_beta.sh +7 -17
- package/deploy_amazon_prod.sh +2 -2
- package/docs/changelog/this-branch.md +0 -36
- package/nginx.conf +2 -22
- package/package.json +1 -4
- package/src/app/app.component.ts +9 -10
- package/src/app/app.module.ts +0 -9
- package/src/app/component/conversation-detail/conversation/conversation.component.html +1 -6
- package/src/app/component/conversation-detail/conversation/conversation.component.scss +2 -2
- package/src/app/component/conversation-detail/conversation/conversation.component.ts +5 -34
- package/src/app/component/conversation-detail/conversation-content/conversation-content.component.html +1 -1
- package/src/app/component/conversation-detail/conversation-content/conversation-content.component.scss +1 -1
- package/src/app/component/conversation-detail/conversation-content/conversation-content.component.ts +0 -1
- package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.html +79 -146
- package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.scss +13 -131
- package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.ts +7 -108
- package/src/app/component/last-message/last-message.component.ts +1 -4
- package/src/app/component/message/audio/audio.component.ts +5 -0
- package/src/app/component/message/bubble-message/bubble-message.component.html +1 -6
- package/src/app/component/message/bubble-message/bubble-message.component.ts +1 -2
- package/src/app/providers/global-settings.service.ts +0 -21
- package/src/app/providers/translator.service.ts +0 -2
- package/src/app/sass/_variables.scss +0 -1
- package/src/app/utils/globals.ts +1 -7
- package/src/assets/i18n/en.json +0 -1
- package/src/assets/i18n/es.json +0 -1
- package/src/assets/i18n/fr.json +0 -1
- package/src/assets/i18n/it.json +0 -1
- package/src/chat21-core/models/message.ts +1 -2
- package/src/chat21-core/providers/firebase/firebase-conversation-handler.ts +2 -3
- package/src/chat21-core/providers/mqtt/mqtt-conversation-handler.ts +0 -12
- package/src/chat21-core/providers/tiledesk/tiledesk-requests.service.ts +1 -1
- package/src/chat21-core/utils/utils-message.ts +0 -7
- package/src/chat21-core/utils/utils.ts +2 -5
- package/src/launch.js +41 -32
- package/src/launch_template.js +41 -32
- package/tsconfig.json +0 -5
- package/src/app/component/message/audio-sync/audio-sync.component.html +0 -19
- package/src/app/component/message/audio-sync/audio-sync.component.scss +0 -65
- package/src/app/component/message/audio-sync/audio-sync.component.spec.ts +0 -23
- package/src/app/component/message/audio-sync/audio-sync.component.ts +0 -197
- package/src/app/providers/voice/STT&TTS/openai-voice.config.ts +0 -12
- package/src/app/providers/voice/STT&TTS/openai-voice.provider.ts +0 -171
- package/src/app/providers/voice/STT&TTS/speech-provider.abstract.ts +0 -39
- package/src/app/providers/voice/audio.types.ts +0 -34
- package/src/app/providers/voice/vad.service.spec.ts +0 -28
- package/src/app/providers/voice/vad.service.ts +0 -70
- package/src/app/providers/voice/voice.service.spec.ts +0 -60
- package/src/app/providers/voice/voice.service.ts +0 -264
- package/src/app/shims/onnxruntime-web-wasm.ts +0 -4
- package/src/assets/onnx/ort-wasm-simd-threaded.mjs +0 -59
- package/src/assets/onnx/ort-wasm-simd-threaded.wasm +0 -0
- package/src/assets/vad/silero_vad_legacy.onnx +0 -0
- 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 &&
|
|
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,
|
|
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
|
|
package/src/app/utils/globals.ts
CHANGED
|
@@ -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
|
-
|
|
452
|
-
this.closeChatInConversation = false;
|
|
446
|
+
|
|
453
447
|
// ============ END: SET EXTERNAL PARAMETERS ==============//
|
|
454
448
|
|
|
455
449
|
|
package/src/assets/i18n/en.json
CHANGED
|
@@ -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
|
}
|
package/src/assets/i18n/es.json
CHANGED
|
@@ -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
|
}
|
package/src/assets/i18n/fr.json
CHANGED
|
@@ -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
|
}
|
package/src/assets/i18n/it.json
CHANGED
|
@@ -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
|
}
|
|
@@ -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
|
-
//
|
|
222
|
-
|
|
223
|
-
|
|
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
|
-
//
|
|
227
|
-
|
|
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(
|
|
244
|
-
console.warn('Error revoking blob URL:',
|
|
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;
|
|
251
|
-
} catch(e) {
|
|
252
|
-
console.warn('Blob URL not available
|
|
270
|
+
return;
|
|
271
|
+
} catch (e) {
|
|
272
|
+
console.warn('Blob URL not available:', e);
|
|
253
273
|
}
|
|
254
274
|
}
|
|
255
|
-
|
|
256
|
-
//
|
|
257
|
-
|
|
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;
|
|
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
|
|
290
|
+
loadIframeContent(ifrm, srcTileDesk);
|
|
282
291
|
|
|
283
292
|
|
|
284
293
|
}
|
package/src/launch_template.js
CHANGED
|
@@ -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
|
-
//
|
|
223
|
-
|
|
224
|
-
|
|
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
|
-
//
|
|
228
|
-
|
|
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(
|
|
245
|
-
console.warn('Error revoking blob URL:',
|
|
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;
|
|
252
|
-
} catch(e) {
|
|
253
|
-
console.warn('Blob URL not available
|
|
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
|
-
//
|
|
269
|
-
if (
|
|
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;
|
|
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
|
|
291
|
+
loadIframeContent(ifrm, srcTileDesk);
|
|
283
292
|
|
|
284
293
|
|
|
285
294
|
}
|
package/tsconfig.json
CHANGED
|
@@ -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
|
-
});
|