embeddedaichatux 2.0.1 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/EmbeddedChat.js +270 -135
- package/package.json +1 -1
package/EmbeddedChat.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
class EmbeddedChat {
|
|
2
|
+
static instanceCounter = 0;
|
|
3
|
+
|
|
2
4
|
constructor(containerDiv, chatId, options) {
|
|
5
|
+
EmbeddedChat.instanceCounter++;
|
|
6
|
+
this.instanceId = `ec_${EmbeddedChat.instanceCounter}_${Date.now()}`;
|
|
7
|
+
|
|
3
8
|
if (!containerDiv) {
|
|
4
9
|
containerDiv = this.createChatContainer();
|
|
5
10
|
}
|
|
@@ -14,7 +19,8 @@
|
|
|
14
19
|
this.width = options.width || 320; // Default width
|
|
15
20
|
this.marginBottom = options.marginBottom || 0;
|
|
16
21
|
this.enableAnimation = options.enableAnimation !== false; // Default to true if not provided
|
|
17
|
-
this.minimizedHeight =
|
|
22
|
+
this.minimizedHeight = "180px"; // Sensible default instead of 30% calculation
|
|
23
|
+
this.hasMeasuredSize = false;
|
|
18
24
|
this.mouseInsideChat = false;
|
|
19
25
|
this.hasRefreshed = false; // Flag to prevent endless loop
|
|
20
26
|
this.conversationId = null;
|
|
@@ -24,19 +30,25 @@
|
|
|
24
30
|
// Determine transition styles
|
|
25
31
|
const transitionStyle = this.enableAnimation ? 'transition: height 0.3s ease, opacity 0.3s ease;' : '';
|
|
26
32
|
|
|
27
|
-
this.
|
|
28
|
-
|
|
33
|
+
this.position = this.options.position || this.containerDiv.dataset.position || 'fixed';
|
|
34
|
+
this.positionStyle = this.position === 'in-place' ?
|
|
35
|
+
`position: relative; width:100%; height:${this.height}px; ${transitionStyle}` :
|
|
29
36
|
`position: fixed; right: 1em; bottom: 0; width: ${this.width}px; z-index: 100000; max-width:90vw; max-height: 90vh; ${transitionStyle}`;
|
|
30
37
|
this.mode = options.mode || 'Chat'; // default to 'chat'
|
|
31
38
|
this.minimizeOnScroll = false; // Default to false
|
|
32
|
-
if (this.mode === 'ContactForm') {
|
|
33
|
-
// Adjust position style for contact form
|
|
34
|
-
this.positionStyle = `width:100%; height:${this.height}px; ${transitionStyle}`;
|
|
39
|
+
if (this.mode === 'ContactForm' || this.mode === 'PartnerOffers') {
|
|
40
|
+
// Adjust position style for contact form/offers - force relative/absolute to occupy container
|
|
41
|
+
this.positionStyle = `position: relative; width:100%; height:${this.height}px; ${transitionStyle}`;
|
|
42
|
+
this.containerDiv.style.position = 'relative';
|
|
35
43
|
this.containerDiv.style.height = `${this.height}px`;
|
|
36
44
|
}
|
|
37
45
|
|
|
38
46
|
this.conversationId = this.getStoredConversationId();
|
|
39
47
|
this.sessionInfo = options.sessionInfo || null;
|
|
48
|
+
|
|
49
|
+
// Initialize window event listeners only once per instance
|
|
50
|
+
this.addWindowEventListeners();
|
|
51
|
+
|
|
40
52
|
this.init();
|
|
41
53
|
}
|
|
42
54
|
|
|
@@ -81,31 +93,35 @@
|
|
|
81
93
|
? this.serverUrl.slice(0, -1)
|
|
82
94
|
: this.serverUrl;
|
|
83
95
|
const baseIframeUrl = `${cleanedServerUrl}/ChatUX/${this.chatId}`;
|
|
84
|
-
const minimizedPositionStyle =
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
height: ${this.minimizedHeight};
|
|
88
|
-
z-index: 100000;
|
|
89
|
-
${this.enableAnimation ? 'transition: height 0.3s ease, opacity 0.3s ease;' : ''}
|
|
90
|
-
`;
|
|
96
|
+
const minimizedPositionStyle = this.position === 'in-place' ?
|
|
97
|
+
`position: relative; width: 100%; height: ${this.minimizedHeight}; ${this.enableAnimation ? 'transition: height 0.3s ease, opacity 0.3s ease;' : ''}` :
|
|
98
|
+
`position: fixed; right: 0; bottom: 0; width: 150px; height: ${this.minimizedHeight}; z-index: 100000; ${this.enableAnimation ? 'transition: height 0.3s ease, opacity 0.3s ease;' : ''}`;
|
|
91
99
|
|
|
92
100
|
const params = {
|
|
93
101
|
isPreview: this.isPreview,
|
|
94
102
|
mode: this.mode,
|
|
95
103
|
locale: this.locale,
|
|
96
|
-
conversationId: this.conversationId
|
|
104
|
+
conversationId: this.conversationId,
|
|
105
|
+
instanceId: this.instanceId,
|
|
106
|
+
customStyle: this.options.customStyle,
|
|
107
|
+
customJs: this.options.customJs
|
|
97
108
|
};
|
|
98
109
|
|
|
110
|
+
const iframeId = `ec-iframe-${this.instanceId}`;
|
|
111
|
+
const minimizedIframeId = `ec-minimized-${this.instanceId}`;
|
|
112
|
+
|
|
99
113
|
const iframeHtml = `
|
|
100
114
|
<iframe
|
|
101
|
-
id="
|
|
115
|
+
id="${iframeId}"
|
|
116
|
+
title="AI chatbot"
|
|
102
117
|
style="${this.positionStyle}; display: none; border:none; overflow:hidden;"
|
|
103
118
|
frameborder="0"
|
|
104
119
|
sandbox="allow-same-origin allow-scripts allow-popups allow-forms allow-top-navigation-by-user-activation"
|
|
105
120
|
src="${this.buildIframeUrl(baseIframeUrl, params)}"
|
|
106
121
|
></iframe>
|
|
107
122
|
<iframe
|
|
108
|
-
id="
|
|
123
|
+
id="${minimizedIframeId}"
|
|
124
|
+
title="AI chatbot"
|
|
109
125
|
style="${minimizedPositionStyle}; display: none; border:none; overflow:hidden;"
|
|
110
126
|
frameborder="0"
|
|
111
127
|
sandbox="allow-same-origin allow-scripts allow-popups allow-forms"
|
|
@@ -115,26 +131,27 @@
|
|
|
115
131
|
|
|
116
132
|
// inject and capture references
|
|
117
133
|
this.containerDiv.innerHTML = iframeHtml;
|
|
118
|
-
this.iframe = this.containerDiv.querySelector(
|
|
119
|
-
this.minimizedIframe = this.containerDiv.querySelector(
|
|
134
|
+
this.iframe = this.containerDiv.querySelector(`#${iframeId}`);
|
|
135
|
+
this.minimizedIframe = this.containerDiv.querySelector(`#${minimizedIframeId}`);
|
|
120
136
|
|
|
121
|
-
//
|
|
122
|
-
|
|
137
|
+
// Wait for main iframe to load
|
|
138
|
+
if (this.iframe) {
|
|
139
|
+
await this.waitForIframeLoad(this.iframe);
|
|
140
|
+
}
|
|
123
141
|
|
|
124
|
-
|
|
125
|
-
this.addEventListeners();
|
|
142
|
+
this.addIframeEventListeners();
|
|
126
143
|
|
|
127
144
|
// Send auth to iframes after load
|
|
128
145
|
await this.postAuthToIframes();
|
|
129
146
|
|
|
130
147
|
// restore your ContactForm logic
|
|
131
|
-
if (this.mode === 'ContactForm') {
|
|
148
|
+
if (this.mode === 'ContactForm' || this.mode === 'PartnerOffers') {
|
|
132
149
|
this.iframe.style.maxWidth = '100%';
|
|
133
150
|
this.iframe.style.display = 'block';
|
|
134
151
|
}
|
|
135
152
|
}
|
|
136
153
|
|
|
137
|
-
|
|
154
|
+
addIframeEventListeners() {
|
|
138
155
|
if (!this.iframe || !this.minimizedIframe) {
|
|
139
156
|
console.error('EmbeddedChat: iframe or minimizedIframe is not defined when trying to add event listeners.', this.iframe, this.minimizedIframe);
|
|
140
157
|
return;
|
|
@@ -143,6 +160,12 @@
|
|
|
143
160
|
this.iframe.addEventListener("mouseleave", () => { this.mouseInsideChat = false; });
|
|
144
161
|
this.minimizedIframe.addEventListener("mouseenter", () => { this.mouseInsideChat = true; });
|
|
145
162
|
this.minimizedIframe.addEventListener("mouseleave", () => { this.mouseInsideChat = false; });
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
addWindowEventListeners() {
|
|
166
|
+
|
|
167
|
+
// Use a flag to ensure window listeners aren't duplicated for this specific instance if setMode is called (though it shouldn't be)
|
|
168
|
+
if (this.windowListenersAdded) return;
|
|
146
169
|
|
|
147
170
|
window.addEventListener("message", (e) => {
|
|
148
171
|
// Only trust messages from our server (when targetOrigin is not "*")
|
|
@@ -156,13 +179,18 @@
|
|
|
156
179
|
}
|
|
157
180
|
});
|
|
158
181
|
|
|
159
|
-
|
|
182
|
+
const handleResizeTrigger = () => {
|
|
160
183
|
this.postResizeMessage();
|
|
161
|
-
}
|
|
184
|
+
};
|
|
162
185
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}
|
|
186
|
+
if (document.readyState === 'complete') {
|
|
187
|
+
handleResizeTrigger();
|
|
188
|
+
} else {
|
|
189
|
+
window.addEventListener("load", handleResizeTrigger);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
window.addEventListener("resize", handleResizeTrigger);
|
|
193
|
+
this.windowListenersAdded = true;
|
|
166
194
|
}
|
|
167
195
|
|
|
168
196
|
postResizeMessage() {
|
|
@@ -170,12 +198,28 @@
|
|
|
170
198
|
this.iframe.contentWindow.postMessage({
|
|
171
199
|
message: "resize",
|
|
172
200
|
width: window.innerWidth, // Ensure correct size
|
|
173
|
-
height: window.innerHeight
|
|
201
|
+
height: window.innerHeight,
|
|
202
|
+
instanceId: this.instanceId
|
|
174
203
|
}, this.targetOrigin);
|
|
175
204
|
}
|
|
176
205
|
}
|
|
177
206
|
|
|
178
207
|
handleMessage(e) {
|
|
208
|
+
// Only trust messages from our server (when targetOrigin is not "*")
|
|
209
|
+
if (this.targetOrigin !== "*" && e.origin !== this.targetOrigin) return;
|
|
210
|
+
|
|
211
|
+
if (typeof e.data !== "object") {
|
|
212
|
+
// Preserve original handling for string messages
|
|
213
|
+
if (typeof e.data === "string") {
|
|
214
|
+
if (e.data === "minimize") {
|
|
215
|
+
this.animateMinimize();
|
|
216
|
+
} else if (e.data === "show" || e.data === "maximize") {
|
|
217
|
+
this.showMaximized();
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
179
223
|
console.log('[EmbeddedChat] Received message:', {
|
|
180
224
|
origin: e.origin,
|
|
181
225
|
type: e.data?.type,
|
|
@@ -184,73 +228,95 @@
|
|
|
184
228
|
data: e.data
|
|
185
229
|
});
|
|
186
230
|
|
|
231
|
+
const data = e.data;
|
|
232
|
+
const msg = (data.message || data.type || "").toString();
|
|
233
|
+
const incomingChatId = (data.chatId || "").toString().toLowerCase();
|
|
234
|
+
const targetChatId = (this.chatId || "").toString().toLowerCase();
|
|
235
|
+
const incomingInstanceId = data.instanceId;
|
|
236
|
+
|
|
237
|
+
// Priority 1: Handle instance-specific routing
|
|
238
|
+
if (incomingInstanceId && incomingInstanceId !== this.instanceId) return;
|
|
239
|
+
|
|
240
|
+
// Priority 2: Bail out if chatId doesn't match and is provided (legacy/fallback)
|
|
241
|
+
if (!incomingInstanceId && incomingChatId && targetChatId && incomingChatId !== targetChatId) return;
|
|
242
|
+
|
|
187
243
|
// Allow the iframe to request a fresh token
|
|
188
|
-
if (
|
|
189
|
-
console.log('[EmbeddedChat] Received requestAuth message, calling postAuthToIframes');
|
|
244
|
+
if (data.type === "requestAuth") {
|
|
190
245
|
this.postAuthToIframes();
|
|
191
246
|
return;
|
|
192
247
|
}
|
|
193
248
|
|
|
194
|
-
|
|
195
|
-
|
|
249
|
+
// Priority 1: Handle minimized size updates (CRITICAL: Bail out early and DO NOT pollute configuration)
|
|
250
|
+
if (msg === "updateMinimizedSize") {
|
|
251
|
+
// Support both new and legacy keys for compatibility with cached scripts
|
|
252
|
+
const h = data.minimizedHeight || data.height;
|
|
253
|
+
const w = data.minimizedWidth || data.width;
|
|
254
|
+
this.updateMinimizedSize(h, w);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const updates = {};
|
|
196
259
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
260
|
+
if (data.type === "setMinimizeOnScroll" || data.minimizeOnScroll !== undefined) {
|
|
261
|
+
const minimizeValue = data.type === "setMinimizeOnScroll" ? data.value : data.minimizeOnScroll;
|
|
262
|
+
this.minimizeOnScroll = minimizeValue === true || minimizeValue === "true";
|
|
263
|
+
}
|
|
201
264
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
265
|
+
if (data.locale) {
|
|
266
|
+
updates.locale = data.locale;
|
|
267
|
+
}
|
|
268
|
+
if (data.width) {
|
|
269
|
+
updates.width = data.width;
|
|
270
|
+
}
|
|
271
|
+
if (data.height) {
|
|
272
|
+
updates.height = data.height;
|
|
273
|
+
}
|
|
274
|
+
if (data.marginBottom) {
|
|
275
|
+
updates.marginBottom = data.marginBottom;
|
|
276
|
+
}
|
|
277
|
+
if (data.scale) {
|
|
278
|
+
updates.scale = data.scale;
|
|
279
|
+
}
|
|
217
280
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
281
|
+
// Apply iframe updates in one go
|
|
282
|
+
if (Object.keys(updates).length > 0) {
|
|
283
|
+
this.applyIframeUpdates(updates);
|
|
284
|
+
}
|
|
222
285
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
} else if (e.data.message === "show" || e.data.message === "maximize") {
|
|
230
|
-
const animate = e.data.animate === true;
|
|
231
|
-
this.showMaximized(animate);
|
|
232
|
-
} else if (e.data.message === "navigate" && e.data.url) {
|
|
233
|
-
// Handle the navigate message
|
|
234
|
-
window.location.href = e.data.url;
|
|
235
|
-
}
|
|
286
|
+
// Handle maximize/minimize/navigate
|
|
287
|
+
if (msg === "minimize") {
|
|
288
|
+
if (typeof this.options.onMinimize === 'function') {
|
|
289
|
+
this.options.onMinimize();
|
|
290
|
+
} else if (this.mode !== 'ContactForm' && this.mode !== 'PartnerOffers') {
|
|
291
|
+
this.animateMinimize();
|
|
236
292
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
293
|
+
} else if (msg === "show" || msg === "maximize") {
|
|
294
|
+
const animate = data.animate === true;
|
|
295
|
+
this.showMaximized(animate);
|
|
296
|
+
} else if (msg === "navigate" && data.url) {
|
|
297
|
+
window.location.href = data.url;
|
|
298
|
+
} else if (data.type === "switchToChat" || msg === "switchToChat") {
|
|
299
|
+
if (typeof this.options.onSwitchToChat === 'function') {
|
|
300
|
+
this.options.onSwitchToChat(data.partner);
|
|
301
|
+
} else {
|
|
302
|
+
this.setMode('Chat', { ...data, initialState: 'Maximized' });
|
|
241
303
|
}
|
|
242
|
-
} else if (
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
this.showMaximized();
|
|
304
|
+
} else if (data.type === "switchToContactForm" || msg === "switchToContactForm") {
|
|
305
|
+
if (typeof this.options.onSwitchToContactForm === 'function') {
|
|
306
|
+
this.options.onSwitchToContactForm(data.partner);
|
|
307
|
+
} else {
|
|
308
|
+
this.setMode('ContactForm', { partner: data.partner, initialState: 'Maximized' });
|
|
248
309
|
}
|
|
249
310
|
}
|
|
311
|
+
|
|
312
|
+
// Handle conversationId update
|
|
313
|
+
if (data.conversationId) {
|
|
314
|
+
this.setConversationId(data.conversationId);
|
|
315
|
+
}
|
|
250
316
|
}
|
|
251
317
|
|
|
252
318
|
animateMinimize() {
|
|
253
|
-
if (this.mode !== 'ContactForm') {
|
|
319
|
+
if (this.mode !== 'ContactForm' && this.mode !== 'PartnerOffers') {
|
|
254
320
|
this.iframe.style.height = this.minimizedHeight;
|
|
255
321
|
this.iframe.style.opacity = '0';
|
|
256
322
|
setTimeout(() => {
|
|
@@ -259,12 +325,39 @@
|
|
|
259
325
|
this.minimizedIframe.style.display = "block";
|
|
260
326
|
this.minimizedIframe.style.height = this.minimizedHeight;
|
|
261
327
|
this.minimizedIframe.style.opacity = '1';
|
|
328
|
+
|
|
329
|
+
// Request a height update after showing
|
|
330
|
+
if (this.minimizedIframe.contentWindow) {
|
|
331
|
+
this.minimizedIframe.contentWindow.postMessage({ message: "requestHeightUpdate", instanceId: this.instanceId }, this.targetOrigin);
|
|
332
|
+
}
|
|
262
333
|
}, this.enableAnimation ? 300 : 0);
|
|
263
334
|
}
|
|
264
335
|
}
|
|
265
336
|
|
|
337
|
+
updateMinimizedSize(contentHeight, contentWidth) {
|
|
338
|
+
if (this.mode === 'ContactForm' || this.mode === 'PartnerOffers') return;
|
|
339
|
+
|
|
340
|
+
this.hasMeasuredSize = true;
|
|
341
|
+
|
|
342
|
+
// Apply height update
|
|
343
|
+
if (contentHeight && contentHeight >= 10) {
|
|
344
|
+
const newHeight = `${contentHeight}px`;
|
|
345
|
+
this.minimizedHeight = newHeight;
|
|
346
|
+
if (this.minimizedIframe) {
|
|
347
|
+
this.minimizedIframe.style.height = newHeight;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Apply width update
|
|
352
|
+
if (contentWidth && contentWidth >= 10) {
|
|
353
|
+
if (this.minimizedIframe) {
|
|
354
|
+
this.minimizedIframe.style.width = `${contentWidth}px`;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
266
359
|
animateMaximize() {
|
|
267
|
-
if (this.mode !== 'ContactForm') {
|
|
360
|
+
if (this.mode !== 'ContactForm' && this.mode !== 'PartnerOffers') {
|
|
268
361
|
// Start the animation for minimizing iframe
|
|
269
362
|
this.minimizedIframe.style.height = `${this.height}px`;
|
|
270
363
|
this.minimizedIframe.style.opacity = '0';
|
|
@@ -298,33 +391,26 @@
|
|
|
298
391
|
// Update width if provided and different
|
|
299
392
|
const parsedWidth = parseInt(width, 10);
|
|
300
393
|
if (!isNaN(parsedWidth) && parsedWidth > 0 && parsedWidth !== this.width) {
|
|
301
|
-
this.width =
|
|
394
|
+
this.width = parsedWidth;
|
|
302
395
|
console.log(`Width updated to: ${this.width}px`);
|
|
303
396
|
|
|
304
|
-
// Apply width
|
|
305
|
-
this.
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
397
|
+
// Apply width only if not in-place
|
|
398
|
+
if (this.position !== 'in-place') {
|
|
399
|
+
this.containerDiv.style.width = `${this.width}px`;
|
|
400
|
+
if (this.iframe) {
|
|
401
|
+
this.iframe.style.width = `${this.width}px`;
|
|
402
|
+
}
|
|
403
|
+
} else {
|
|
404
|
+
this.containerDiv.style.width = '100%';
|
|
405
|
+
if (this.iframe) {
|
|
406
|
+
this.iframe.style.width = '100%';
|
|
407
|
+
}
|
|
315
408
|
}
|
|
316
409
|
}
|
|
317
410
|
|
|
318
411
|
// Apply scale if provided
|
|
319
412
|
if (typeof scale === 'number' && scale > 0) {
|
|
320
|
-
|
|
321
|
-
this.iframe.style.transform = `scale(${scale})`;
|
|
322
|
-
this.iframe.style.transformOrigin = "bottom right";
|
|
323
|
-
}
|
|
324
|
-
if (this.minimizedIframe) {
|
|
325
|
-
this.minimizedIframe.style.transform = `scale(${scale})`;
|
|
326
|
-
this.minimizedIframe.style.transformOrigin = "bottom right";
|
|
327
|
-
}
|
|
413
|
+
this.applyScale(scale);
|
|
328
414
|
console.log(`Scale applied: ${scale}`);
|
|
329
415
|
}
|
|
330
416
|
|
|
@@ -342,28 +428,43 @@
|
|
|
342
428
|
|
|
343
429
|
// Clamp so that height + marginBottom doesn't exceed 90% of viewport
|
|
344
430
|
const viewportHeight = window.innerHeight;
|
|
345
|
-
|
|
346
|
-
|
|
431
|
+
let effectiveHeight = parsedHeight;
|
|
432
|
+
if (effectiveHeight + parsedMarginBottom > 0.9 * viewportHeight) {
|
|
433
|
+
effectiveHeight = Math.max(100, 0.9 * viewportHeight - parsedMarginBottom);
|
|
347
434
|
}
|
|
348
435
|
|
|
349
436
|
// Only apply if there's an actual change
|
|
350
437
|
if (parsedHeight !== this.height || parsedMarginBottom !== this.marginBottom) {
|
|
351
438
|
this.height = parsedHeight;
|
|
352
439
|
this.marginBottom = parsedMarginBottom;
|
|
353
|
-
this.minimizedHeight = `${this.height * 0.3}px`;
|
|
354
440
|
|
|
355
|
-
|
|
441
|
+
// Only use the 30% estimate if we haven't received a real measurement yet
|
|
442
|
+
if (!this.hasMeasuredSize) {
|
|
443
|
+
this.minimizedHeight = `${this.height * 0.3}px`;
|
|
444
|
+
}
|
|
356
445
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
446
|
+
console.log(`Height updated to: ${this.height}px (clamped to ${effectiveHeight}px for display), marginBottom: ${this.marginBottom}px`);
|
|
447
|
+
|
|
448
|
+
// Apply the updated height/marginBottom
|
|
449
|
+
if (this.mode !== 'ContactForm' && this.mode !== 'PartnerOffers') {
|
|
450
|
+
if (this.position === 'in-place') {
|
|
360
451
|
// "in-place" uses full width, sets containerDiv height
|
|
361
|
-
this.containerDiv.style.
|
|
452
|
+
this.containerDiv.style.position = 'relative';
|
|
453
|
+
this.containerDiv.style.width = '100%';
|
|
454
|
+
this.containerDiv.style.height = `${effectiveHeight}px`;
|
|
362
455
|
if (this.iframe) {
|
|
363
|
-
this.iframe.style.
|
|
456
|
+
this.iframe.style.position = 'relative';
|
|
457
|
+
this.iframe.style.width = '100%';
|
|
458
|
+
this.iframe.style.height = `${effectiveHeight}px`;
|
|
459
|
+
this.iframe.style.bottom = 'unset';
|
|
460
|
+
this.iframe.style.right = 'unset';
|
|
364
461
|
}
|
|
365
462
|
if (this.minimizedIframe) {
|
|
463
|
+
this.minimizedIframe.style.position = 'relative';
|
|
464
|
+
this.minimizedIframe.style.width = '100%';
|
|
366
465
|
this.minimizedIframe.style.height = this.minimizedHeight;
|
|
466
|
+
this.minimizedIframe.style.bottom = 'unset';
|
|
467
|
+
this.minimizedIframe.style.right = 'unset';
|
|
367
468
|
}
|
|
368
469
|
} else {
|
|
369
470
|
// position: fixed (typical floating chat)
|
|
@@ -392,7 +493,8 @@
|
|
|
392
493
|
if (this.iframe.contentWindow) {
|
|
393
494
|
this.iframe.contentWindow.postMessage({
|
|
394
495
|
message: "show",
|
|
395
|
-
sessionInfo: this.sessionInfo || null
|
|
496
|
+
sessionInfo: this.sessionInfo || null,
|
|
497
|
+
instanceId: this.instanceId
|
|
396
498
|
}, this.targetOrigin);
|
|
397
499
|
} else {
|
|
398
500
|
// Schedule a single retry with a delay
|
|
@@ -400,7 +502,8 @@
|
|
|
400
502
|
if (this.iframe.contentWindow) {
|
|
401
503
|
this.iframe.contentWindow.postMessage({
|
|
402
504
|
message: "show",
|
|
403
|
-
sessionInfo: this.sessionInfo || null
|
|
505
|
+
sessionInfo: this.sessionInfo || null,
|
|
506
|
+
instanceId: this.instanceId
|
|
404
507
|
}, this.targetOrigin);
|
|
405
508
|
} else {
|
|
406
509
|
console.warn("iframe contentWindow is not available.");
|
|
@@ -425,16 +528,21 @@
|
|
|
425
528
|
}
|
|
426
529
|
|
|
427
530
|
applyScale(scale) {
|
|
428
|
-
if (this.mode !== 'ContactForm') {
|
|
429
|
-
this.
|
|
430
|
-
this.iframe
|
|
431
|
-
|
|
432
|
-
|
|
531
|
+
if (this.mode !== 'ContactForm' && this.mode !== 'PartnerOffers') {
|
|
532
|
+
const origin = this.position === 'in-place' ? 'top center' : 'bottom right';
|
|
533
|
+
if (this.iframe) {
|
|
534
|
+
this.iframe.style.transform = `scale(${scale})`;
|
|
535
|
+
this.iframe.style.transformOrigin = origin;
|
|
536
|
+
}
|
|
537
|
+
if (this.minimizedIframe) {
|
|
538
|
+
this.minimizedIframe.style.transform = `scale(${scale})`;
|
|
539
|
+
this.minimizedIframe.style.transformOrigin = origin;
|
|
540
|
+
}
|
|
433
541
|
}
|
|
434
542
|
}
|
|
435
543
|
|
|
436
544
|
minimizeOnScrollAction() {
|
|
437
|
-
if (this.mode !== 'ContactForm' && this.iframe.style.display !== "none") {
|
|
545
|
+
if (this.mode !== 'ContactForm' && this.mode !== 'PartnerOffers' && this.iframe.style.display !== "none") {
|
|
438
546
|
this.animateMinimize();
|
|
439
547
|
}
|
|
440
548
|
}
|
|
@@ -445,7 +553,7 @@
|
|
|
445
553
|
|
|
446
554
|
// Send session info immediately if the chat is already maximized
|
|
447
555
|
if (this.iframe?.contentWindow && this.iframe.style.display !== "none") {
|
|
448
|
-
this.iframe.contentWindow.postMessage({ type: 'setSessionInfo', sessionInfo: this.sessionInfo }, this.targetOrigin);
|
|
556
|
+
this.iframe.contentWindow.postMessage({ type: 'setSessionInfo', sessionInfo: this.sessionInfo, instanceId: this.instanceId }, this.targetOrigin);
|
|
449
557
|
}
|
|
450
558
|
}
|
|
451
559
|
|
|
@@ -464,8 +572,8 @@
|
|
|
464
572
|
urlParams.set('isPreview', 'true');
|
|
465
573
|
}
|
|
466
574
|
|
|
467
|
-
if (params.mode === 'ContactForm') {
|
|
468
|
-
urlParams.set('mode',
|
|
575
|
+
if (params.mode === 'ContactForm' || params.mode === 'PartnerOffers' || params.mode === 'Chat') {
|
|
576
|
+
urlParams.set('mode', params.mode);
|
|
469
577
|
}
|
|
470
578
|
|
|
471
579
|
if (params.locale) {
|
|
@@ -485,17 +593,12 @@
|
|
|
485
593
|
return `${baseIframeUrl}?${urlParams.toString()}`;
|
|
486
594
|
}
|
|
487
595
|
|
|
488
|
-
waitForIframeLoad(iframe, timeout =
|
|
489
|
-
return new Promise((resolve
|
|
490
|
-
// Check if the iframe is already loaded
|
|
491
|
-
if (iframe.contentDocument || iframe.contentWindow) {
|
|
492
|
-
resolve();
|
|
493
|
-
return;
|
|
494
|
-
}
|
|
495
|
-
|
|
596
|
+
waitForIframeLoad(iframe, timeout = 10000) {
|
|
597
|
+
return new Promise((resolve) => {
|
|
496
598
|
// Set up a timeout to avoid waiting indefinitely
|
|
497
599
|
const timeoutId = setTimeout(() => {
|
|
498
|
-
|
|
600
|
+
console.warn('EmbeddedChat: Iframe load timeout, proceeding with initialization.');
|
|
601
|
+
resolve();
|
|
499
602
|
}, timeout);
|
|
500
603
|
|
|
501
604
|
// Add the load event listener
|
|
@@ -514,7 +617,6 @@
|
|
|
514
617
|
}
|
|
515
618
|
|
|
516
619
|
try {
|
|
517
|
-
console.log('[EmbeddedChat] Calling userTokenProvider...');
|
|
518
620
|
const userToken = await this.userTokenProvider();
|
|
519
621
|
|
|
520
622
|
if (!userToken) {
|
|
@@ -522,14 +624,13 @@
|
|
|
522
624
|
return;
|
|
523
625
|
}
|
|
524
626
|
|
|
525
|
-
console.log('[EmbeddedChat] Got user token, length:', userToken?.length || 0);
|
|
526
|
-
|
|
527
627
|
if (this.iframe?.contentWindow) {
|
|
528
628
|
console.log('[EmbeddedChat] Sending auth message to iframe with targetOrigin:', this.targetOrigin);
|
|
529
629
|
this.iframe.contentWindow.postMessage({
|
|
530
630
|
type: 'auth',
|
|
531
631
|
userToken: userToken,
|
|
532
|
-
chatId: this.chatId
|
|
632
|
+
chatId: this.chatId,
|
|
633
|
+
instanceId: this.instanceId
|
|
533
634
|
}, this.targetOrigin);
|
|
534
635
|
console.log('[EmbeddedChat] Auth message sent successfully');
|
|
535
636
|
} else {
|
|
@@ -540,6 +641,33 @@
|
|
|
540
641
|
console.error('[EmbeddedChat] Failed to get user token:', err);
|
|
541
642
|
}
|
|
542
643
|
}
|
|
644
|
+
|
|
645
|
+
setMode(newMode, options = {}) {
|
|
646
|
+
if (this.mode === newMode && (!options.chatId || options.chatId === this.chatId)) return;
|
|
647
|
+
|
|
648
|
+
console.log(`[EmbeddedChat] Setting mode to ${newMode}`, options);
|
|
649
|
+
this.mode = newMode;
|
|
650
|
+
if (options.chatId) {
|
|
651
|
+
this.chatId = options.chatId;
|
|
652
|
+
}
|
|
653
|
+
this.options = { ...this.options, ...options };
|
|
654
|
+
const transitionStyle = this.enableAnimation ? 'transition: height 0.3s ease, opacity 0.3s ease;' : '';
|
|
655
|
+
if (this.mode === 'ContactForm' || this.mode === 'PartnerOffers') {
|
|
656
|
+
this.positionStyle = `position: relative; width:100%; height:${this.height}px; ${transitionStyle}`;
|
|
657
|
+
this.containerDiv.style.position = 'relative';
|
|
658
|
+
this.containerDiv.style.height = `${this.height}px`;
|
|
659
|
+
} else {
|
|
660
|
+
this.positionStyle = this.position === 'in-place' ?
|
|
661
|
+
`position: relative; width:100%; height:${this.height}px; ${transitionStyle}` :
|
|
662
|
+
`position: fixed; right: 1em; bottom: 0; width: ${this.width}px; z-index: 100000; max-width:90vw; max-height: 90vh; ${transitionStyle}`;
|
|
663
|
+
if (this.position === 'in-place') {
|
|
664
|
+
this.containerDiv.style.position = 'relative';
|
|
665
|
+
this.containerDiv.style.width = '100%';
|
|
666
|
+
this.containerDiv.style.height = `${this.height}px`;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
this.updateIframes();
|
|
670
|
+
}
|
|
543
671
|
}
|
|
544
672
|
|
|
545
673
|
export function initEmbeddedChat(containerDiv, chatId, options) {
|
|
@@ -550,3 +678,10 @@ export function initContactForm(containerDiv, chatId, options) {
|
|
|
550
678
|
const clonedOptions = { ...options, mode: 'ContactForm' };
|
|
551
679
|
return new EmbeddedChat(containerDiv, chatId, clonedOptions);
|
|
552
680
|
}
|
|
681
|
+
|
|
682
|
+
export function initOffers(options = {}) {
|
|
683
|
+
const chatId = options.chatConfigId;
|
|
684
|
+
const mergedOptions = { ...options, mode: 'PartnerOffers', height: options.height || 500 };
|
|
685
|
+
return new EmbeddedChat(options.container, chatId, mergedOptions);
|
|
686
|
+
}
|
|
687
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "embeddedaichatux",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "A lightweight and customizable embedded AI chat UI component that seamlessly integrates into web applications, offering minimized and expanded views, with iframe-based content rendering.",
|
|
5
5
|
"main": "EmbeddedChat.js",
|
|
6
6
|
"scripts": {
|