embeddedaichatux 2.0.1 → 2.1.1
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 +118 -73
- package/package.json +1 -1
package/EmbeddedChat.js
CHANGED
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
this.width = options.width || 320; // Default width
|
|
15
15
|
this.marginBottom = options.marginBottom || 0;
|
|
16
16
|
this.enableAnimation = options.enableAnimation !== false; // Default to true if not provided
|
|
17
|
-
this.minimizedHeight =
|
|
17
|
+
this.minimizedHeight = "180px"; // Sensible default instead of 30% calculation
|
|
18
|
+
this.hasMeasuredSize = false;
|
|
18
19
|
this.mouseInsideChat = false;
|
|
19
20
|
this.hasRefreshed = false; // Flag to prevent endless loop
|
|
20
21
|
this.conversationId = null;
|
|
@@ -83,7 +84,7 @@
|
|
|
83
84
|
const baseIframeUrl = `${cleanedServerUrl}/ChatUX/${this.chatId}`;
|
|
84
85
|
const minimizedPositionStyle = `
|
|
85
86
|
position: fixed; right: 0; bottom: 0;
|
|
86
|
-
width:
|
|
87
|
+
width: 150px;
|
|
87
88
|
height: ${this.minimizedHeight};
|
|
88
89
|
z-index: 100000;
|
|
89
90
|
${this.enableAnimation ? 'transition: height 0.3s ease, opacity 0.3s ease;' : ''}
|
|
@@ -115,13 +116,14 @@
|
|
|
115
116
|
|
|
116
117
|
// inject and capture references
|
|
117
118
|
this.containerDiv.innerHTML = iframeHtml;
|
|
118
|
-
this.iframe = this.containerDiv.querySelector(
|
|
119
|
-
this.minimizedIframe = this.containerDiv.querySelector(
|
|
119
|
+
this.iframe = this.containerDiv.querySelector("#embedded-chat");
|
|
120
|
+
this.minimizedIframe = this.containerDiv.querySelector("#embedded-chat-minimized");
|
|
120
121
|
|
|
121
|
-
//
|
|
122
|
-
|
|
122
|
+
// Wait for main iframe to load
|
|
123
|
+
if (this.iframe) {
|
|
124
|
+
await this.waitForIframeLoad(this.iframe);
|
|
125
|
+
}
|
|
123
126
|
|
|
124
|
-
// now that this.iframe & this.minimizedIframe exist, hook up events
|
|
125
127
|
this.addEventListeners();
|
|
126
128
|
|
|
127
129
|
// Send auth to iframes after load
|
|
@@ -176,6 +178,21 @@
|
|
|
176
178
|
}
|
|
177
179
|
|
|
178
180
|
handleMessage(e) {
|
|
181
|
+
// Only trust messages from our server (when targetOrigin is not "*")
|
|
182
|
+
if (this.targetOrigin !== "*" && e.origin !== this.targetOrigin) return;
|
|
183
|
+
|
|
184
|
+
if (typeof e.data !== "object") {
|
|
185
|
+
// Preserve original handling for string messages
|
|
186
|
+
if (typeof e.data === "string") {
|
|
187
|
+
if (e.data === "minimize") {
|
|
188
|
+
this.animateMinimize();
|
|
189
|
+
} else if (e.data === "show" || e.data === "maximize") {
|
|
190
|
+
this.showMaximized();
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
179
196
|
console.log('[EmbeddedChat] Received message:', {
|
|
180
197
|
origin: e.origin,
|
|
181
198
|
type: e.data?.type,
|
|
@@ -184,68 +201,72 @@
|
|
|
184
201
|
data: e.data
|
|
185
202
|
});
|
|
186
203
|
|
|
204
|
+
const data = e.data;
|
|
205
|
+
const msg = (data.message || data.type || "").toString();
|
|
206
|
+
const incomingChatId = (data.chatId || "").toString().toLowerCase();
|
|
207
|
+
const targetChatId = (this.chatId || "").toString().toLowerCase();
|
|
208
|
+
|
|
209
|
+
// Bail out if chatId doesn't match and is provided
|
|
210
|
+
if (incomingChatId && targetChatId && incomingChatId !== targetChatId) return;
|
|
211
|
+
|
|
187
212
|
// Allow the iframe to request a fresh token
|
|
188
|
-
if (
|
|
189
|
-
console.log('[EmbeddedChat] Received requestAuth message, calling postAuthToIframes');
|
|
213
|
+
if (data.type === "requestAuth") {
|
|
190
214
|
this.postAuthToIframes();
|
|
191
215
|
return;
|
|
192
216
|
}
|
|
193
217
|
|
|
194
|
-
|
|
195
|
-
|
|
218
|
+
// Priority 1: Handle minimized size updates (CRITICAL: Bail out early and DO NOT pollute configuration)
|
|
219
|
+
if (msg === "updateMinimizedSize") {
|
|
220
|
+
// Support both new and legacy keys for compatibility with cached scripts
|
|
221
|
+
const h = data.minimizedHeight || data.height;
|
|
222
|
+
const w = data.minimizedWidth || data.width;
|
|
223
|
+
this.updateMinimizedSize(h, w);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
196
226
|
|
|
197
|
-
|
|
198
|
-
const minimizeValue = e.data.type === "setMinimizeOnScroll" ? e.data.value : e.data.minimizeOnScroll;
|
|
199
|
-
this.minimizeOnScroll = minimizeValue === true || minimizeValue === "true";
|
|
200
|
-
}
|
|
227
|
+
const updates = {};
|
|
201
228
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
updates.width = e.data.width;
|
|
207
|
-
}
|
|
208
|
-
if (e.data.height) {
|
|
209
|
-
updates.height = e.data.height;
|
|
210
|
-
}
|
|
211
|
-
if (e.data.marginBottom) {
|
|
212
|
-
updates.marginBottom = e.data.marginBottom;
|
|
213
|
-
}
|
|
214
|
-
if (e.data.scale) {
|
|
215
|
-
updates.scale = e.data.scale;
|
|
216
|
-
}
|
|
229
|
+
if (data.type === "setMinimizeOnScroll" || data.minimizeOnScroll !== undefined) {
|
|
230
|
+
const minimizeValue = data.type === "setMinimizeOnScroll" ? data.value : data.minimizeOnScroll;
|
|
231
|
+
this.minimizeOnScroll = minimizeValue === true || minimizeValue === "true";
|
|
232
|
+
}
|
|
217
233
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
234
|
+
if (data.locale) {
|
|
235
|
+
updates.locale = data.locale;
|
|
236
|
+
}
|
|
237
|
+
if (data.width) {
|
|
238
|
+
updates.width = data.width;
|
|
239
|
+
}
|
|
240
|
+
if (data.height) {
|
|
241
|
+
updates.height = data.height;
|
|
242
|
+
}
|
|
243
|
+
if (data.marginBottom) {
|
|
244
|
+
updates.marginBottom = data.marginBottom;
|
|
245
|
+
}
|
|
246
|
+
if (data.scale) {
|
|
247
|
+
updates.scale = data.scale;
|
|
248
|
+
}
|
|
222
249
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
this.animateMinimize();
|
|
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
|
-
}
|
|
236
|
-
}
|
|
250
|
+
// Apply iframe updates in one go
|
|
251
|
+
if (Object.keys(updates).length > 0) {
|
|
252
|
+
this.applyIframeUpdates(updates);
|
|
253
|
+
}
|
|
237
254
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
242
|
-
} else if (typeof e.data === "string") {
|
|
243
|
-
// Preserve original handling for string messages
|
|
244
|
-
if (e.data === "minimize") {
|
|
255
|
+
// Handle maximize/minimize/navigate
|
|
256
|
+
if (msg === "minimize") {
|
|
257
|
+
if (this.mode !== 'ContactForm') {
|
|
245
258
|
this.animateMinimize();
|
|
246
|
-
} else if (e.data === "show" || e.data === "maximize") {
|
|
247
|
-
this.showMaximized();
|
|
248
259
|
}
|
|
260
|
+
} else if (msg === "show" || msg === "maximize") {
|
|
261
|
+
const animate = data.animate === true;
|
|
262
|
+
this.showMaximized(animate);
|
|
263
|
+
} else if (msg === "navigate" && data.url) {
|
|
264
|
+
window.location.href = data.url;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Handle conversationId update
|
|
268
|
+
if (data.conversationId) {
|
|
269
|
+
this.setConversationId(data.conversationId);
|
|
249
270
|
}
|
|
250
271
|
}
|
|
251
272
|
|
|
@@ -259,10 +280,37 @@
|
|
|
259
280
|
this.minimizedIframe.style.display = "block";
|
|
260
281
|
this.minimizedIframe.style.height = this.minimizedHeight;
|
|
261
282
|
this.minimizedIframe.style.opacity = '1';
|
|
283
|
+
|
|
284
|
+
// Request a height update after showing
|
|
285
|
+
if (this.minimizedIframe.contentWindow) {
|
|
286
|
+
this.minimizedIframe.contentWindow.postMessage({ message: "requestHeightUpdate" }, this.targetOrigin);
|
|
287
|
+
}
|
|
262
288
|
}, this.enableAnimation ? 300 : 0);
|
|
263
289
|
}
|
|
264
290
|
}
|
|
265
291
|
|
|
292
|
+
updateMinimizedSize(contentHeight, contentWidth) {
|
|
293
|
+
if (this.mode === 'ContactForm') return;
|
|
294
|
+
|
|
295
|
+
this.hasMeasuredSize = true;
|
|
296
|
+
|
|
297
|
+
// Apply height update
|
|
298
|
+
if (contentHeight && contentHeight >= 10) {
|
|
299
|
+
const newHeight = `${contentHeight}px`;
|
|
300
|
+
this.minimizedHeight = newHeight;
|
|
301
|
+
if (this.minimizedIframe) {
|
|
302
|
+
this.minimizedIframe.style.height = newHeight;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Apply width update
|
|
307
|
+
if (contentWidth && contentWidth >= 10) {
|
|
308
|
+
if (this.minimizedIframe) {
|
|
309
|
+
this.minimizedIframe.style.width = `${contentWidth}px`;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
266
314
|
animateMaximize() {
|
|
267
315
|
if (this.mode !== 'ContactForm') {
|
|
268
316
|
// Start the animation for minimizing iframe
|
|
@@ -298,7 +346,7 @@
|
|
|
298
346
|
// Update width if provided and different
|
|
299
347
|
const parsedWidth = parseInt(width, 10);
|
|
300
348
|
if (!isNaN(parsedWidth) && parsedWidth > 0 && parsedWidth !== this.width) {
|
|
301
|
-
this.width =
|
|
349
|
+
this.width = parsedWidth;
|
|
302
350
|
console.log(`Width updated to: ${this.width}px`);
|
|
303
351
|
|
|
304
352
|
// Apply width to container
|
|
@@ -308,11 +356,6 @@
|
|
|
308
356
|
if (this.iframe) {
|
|
309
357
|
this.iframe.style.width = `${this.width}px`;
|
|
310
358
|
}
|
|
311
|
-
|
|
312
|
-
// Apply width to the minimized iframe
|
|
313
|
-
if (this.minimizedIframe) {
|
|
314
|
-
this.minimizedIframe.style.width = `${this.width}px`;
|
|
315
|
-
}
|
|
316
359
|
}
|
|
317
360
|
|
|
318
361
|
// Apply scale if provided
|
|
@@ -342,25 +385,30 @@
|
|
|
342
385
|
|
|
343
386
|
// Clamp so that height + marginBottom doesn't exceed 90% of viewport
|
|
344
387
|
const viewportHeight = window.innerHeight;
|
|
345
|
-
|
|
346
|
-
|
|
388
|
+
let effectiveHeight = parsedHeight;
|
|
389
|
+
if (effectiveHeight + parsedMarginBottom > 0.9 * viewportHeight) {
|
|
390
|
+
effectiveHeight = Math.max(100, 0.9 * viewportHeight - parsedMarginBottom);
|
|
347
391
|
}
|
|
348
392
|
|
|
349
393
|
// Only apply if there's an actual change
|
|
350
394
|
if (parsedHeight !== this.height || parsedMarginBottom !== this.marginBottom) {
|
|
351
395
|
this.height = parsedHeight;
|
|
352
396
|
this.marginBottom = parsedMarginBottom;
|
|
353
|
-
this.minimizedHeight = `${this.height * 0.3}px`;
|
|
354
397
|
|
|
355
|
-
|
|
398
|
+
// Only use the 30% estimate if we haven't received a real measurement yet
|
|
399
|
+
if (!this.hasMeasuredSize) {
|
|
400
|
+
this.minimizedHeight = `${this.height * 0.3}px`;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
console.log(`Height updated to: ${this.height}px (clamped to ${effectiveHeight}px for display), marginBottom: ${this.marginBottom}px`);
|
|
356
404
|
|
|
357
|
-
// Apply the updated height/marginBottom
|
|
405
|
+
// Apply the updated height/marginBottom
|
|
358
406
|
if (this.mode !== 'ContactForm') {
|
|
359
407
|
if (this.containerDiv.dataset.position === 'in-place') {
|
|
360
408
|
// "in-place" uses full width, sets containerDiv height
|
|
361
|
-
this.containerDiv.style.height = `${
|
|
409
|
+
this.containerDiv.style.height = `${effectiveHeight}px`;
|
|
362
410
|
if (this.iframe) {
|
|
363
|
-
this.iframe.style.height = `${
|
|
411
|
+
this.iframe.style.height = `${effectiveHeight}px`;
|
|
364
412
|
}
|
|
365
413
|
if (this.minimizedIframe) {
|
|
366
414
|
this.minimizedIframe.style.height = this.minimizedHeight;
|
|
@@ -514,7 +562,6 @@
|
|
|
514
562
|
}
|
|
515
563
|
|
|
516
564
|
try {
|
|
517
|
-
console.log('[EmbeddedChat] Calling userTokenProvider...');
|
|
518
565
|
const userToken = await this.userTokenProvider();
|
|
519
566
|
|
|
520
567
|
if (!userToken) {
|
|
@@ -522,8 +569,6 @@
|
|
|
522
569
|
return;
|
|
523
570
|
}
|
|
524
571
|
|
|
525
|
-
console.log('[EmbeddedChat] Got user token, length:', userToken?.length || 0);
|
|
526
|
-
|
|
527
572
|
if (this.iframe?.contentWindow) {
|
|
528
573
|
console.log('[EmbeddedChat] Sending auth message to iframe with targetOrigin:', this.targetOrigin);
|
|
529
574
|
this.iframe.contentWindow.postMessage({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "embeddedaichatux",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
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": {
|