embeddedaichatux 2.0.0 → 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.
Files changed (2) hide show
  1. package/EmbeddedChat.js +120 -80
  2. package/package.json +1 -1
package/EmbeddedChat.js CHANGED
@@ -14,17 +14,13 @@
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 = `${this.height * 0.3}px`; // 30% of the full height
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;
21
22
  this.userTokenProvider = options.userTokenProvider;
22
-
23
- try {
24
- this.targetOrigin = new URL(this.serverUrl).origin;
25
- } catch {
26
- this.targetOrigin = "*";
27
- }
23
+ this.targetOrigin = "*";
28
24
 
29
25
  // Determine transition styles
30
26
  const transitionStyle = this.enableAnimation ? 'transition: height 0.3s ease, opacity 0.3s ease;' : '';
@@ -46,7 +42,7 @@
46
42
  }
47
43
 
48
44
  isSafari() {
49
- var ua = navigator.userAgent.toLowerCase();
45
+ const ua = navigator.userAgent.toLowerCase();
50
46
  return ua.indexOf('safari') != -1 && ua.indexOf('chrome') == -1;
51
47
  }
52
48
 
@@ -88,7 +84,7 @@
88
84
  const baseIframeUrl = `${cleanedServerUrl}/ChatUX/${this.chatId}`;
89
85
  const minimizedPositionStyle = `
90
86
  position: fixed; right: 0; bottom: 0;
91
- width: ${this.width}px;
87
+ width: 150px;
92
88
  height: ${this.minimizedHeight};
93
89
  z-index: 100000;
94
90
  ${this.enableAnimation ? 'transition: height 0.3s ease, opacity 0.3s ease;' : ''}
@@ -120,13 +116,14 @@
120
116
 
121
117
  // inject and capture references
122
118
  this.containerDiv.innerHTML = iframeHtml;
123
- this.iframe = this.containerDiv.querySelector('#embedded-chat');
124
- this.minimizedIframe = this.containerDiv.querySelector('#embedded-chat-minimized');
119
+ this.iframe = this.containerDiv.querySelector("#embedded-chat");
120
+ this.minimizedIframe = this.containerDiv.querySelector("#embedded-chat-minimized");
125
121
 
126
- // wait for the real <iframe> element to load
127
- await this.waitForIframeLoad(this.iframe);
122
+ // Wait for main iframe to load
123
+ if (this.iframe) {
124
+ await this.waitForIframeLoad(this.iframe);
125
+ }
128
126
 
129
- // now that this.iframe & this.minimizedIframe exist, hook up events
130
127
  this.addEventListeners();
131
128
 
132
129
  // Send auth to iframes after load
@@ -181,6 +178,21 @@
181
178
  }
182
179
 
183
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
+
184
196
  console.log('[EmbeddedChat] Received message:', {
185
197
  origin: e.origin,
186
198
  type: e.data?.type,
@@ -189,68 +201,72 @@
189
201
  data: e.data
190
202
  });
191
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
+
192
212
  // Allow the iframe to request a fresh token
193
- if (typeof e.data === "object" && e.data?.type === "requestAuth") {
194
- console.log('[EmbeddedChat] Received requestAuth message, calling postAuthToIframes');
213
+ if (data.type === "requestAuth") {
195
214
  this.postAuthToIframes();
196
215
  return;
197
216
  }
198
217
 
199
- if (typeof e.data === "object" && (!e.data.chatId || e.data.chatId === this.chatId)) {
200
- const updates = {};
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
+ }
201
226
 
202
- if (e.data.type === "setMinimizeOnScroll" || e.data.minimizeOnScroll !== undefined) {
203
- const minimizeValue = e.data.type === "setMinimizeOnScroll" ? e.data.value : e.data.minimizeOnScroll;
204
- this.minimizeOnScroll = minimizeValue === true || minimizeValue === "true";
205
- }
227
+ const updates = {};
206
228
 
207
- if (e.data.locale) {
208
- updates.locale = e.data.locale;
209
- }
210
- if (e.data.width) {
211
- updates.width = e.data.width;
212
- }
213
- if (e.data.height) {
214
- updates.height = e.data.height;
215
- }
216
- if (e.data.marginBottom) {
217
- updates.marginBottom = e.data.marginBottom;
218
- }
219
- if (e.data.scale) {
220
- updates.scale = e.data.scale;
221
- }
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
+ }
222
233
 
223
- // Apply iframe updates in one go
224
- if (Object.keys(updates).length > 0) {
225
- this.applyIframeUpdates(updates);
226
- }
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
+ }
227
249
 
228
- // Handle maximize/minimize
229
- if (e.data.message) {
230
- if (e.data.message === "minimize") {
231
- if (this.mode !== 'ContactForm') {
232
- this.animateMinimize();
233
- }
234
- } else if (e.data.message === "show" || e.data.message === "maximize") {
235
- const animate = e.data.animate === true;
236
- this.showMaximized(animate);
237
- } else if (e.data.message === "navigate" && e.data.url) {
238
- // Handle the navigate message
239
- window.location.href = e.data.url;
240
- }
241
- }
250
+ // Apply iframe updates in one go
251
+ if (Object.keys(updates).length > 0) {
252
+ this.applyIframeUpdates(updates);
253
+ }
242
254
 
243
- // Handle conversationId update
244
- if (e.data.conversationId) {
245
- this.setConversationId(e.data.conversationId);
246
- }
247
- } else if (typeof e.data === "string") {
248
- // Preserve original handling for string messages
249
- if (e.data === "minimize") {
255
+ // Handle maximize/minimize/navigate
256
+ if (msg === "minimize") {
257
+ if (this.mode !== 'ContactForm') {
250
258
  this.animateMinimize();
251
- } else if (e.data === "show" || e.data === "maximize") {
252
- this.showMaximized();
253
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);
254
270
  }
255
271
  }
256
272
 
@@ -264,10 +280,37 @@
264
280
  this.minimizedIframe.style.display = "block";
265
281
  this.minimizedIframe.style.height = this.minimizedHeight;
266
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
+ }
267
288
  }, this.enableAnimation ? 300 : 0);
268
289
  }
269
290
  }
270
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
+
271
314
  animateMaximize() {
272
315
  if (this.mode !== 'ContactForm') {
273
316
  // Start the animation for minimizing iframe
@@ -303,7 +346,7 @@
303
346
  // Update width if provided and different
304
347
  const parsedWidth = parseInt(width, 10);
305
348
  if (!isNaN(parsedWidth) && parsedWidth > 0 && parsedWidth !== this.width) {
306
- this.width = Math.max(parsedWidth, 320);
349
+ this.width = parsedWidth;
307
350
  console.log(`Width updated to: ${this.width}px`);
308
351
 
309
352
  // Apply width to container
@@ -313,11 +356,6 @@
313
356
  if (this.iframe) {
314
357
  this.iframe.style.width = `${this.width}px`;
315
358
  }
316
-
317
- // Apply width to the minimized iframe
318
- if (this.minimizedIframe) {
319
- this.minimizedIframe.style.width = `${this.width}px`;
320
- }
321
359
  }
322
360
 
323
361
  // Apply scale if provided
@@ -347,25 +385,30 @@
347
385
 
348
386
  // Clamp so that height + marginBottom doesn't exceed 90% of viewport
349
387
  const viewportHeight = window.innerHeight;
350
- if (parsedHeight + parsedMarginBottom > 0.9 * viewportHeight) {
351
- parsedHeight = Math.max(0, 0.9 * viewportHeight - parsedMarginBottom);
388
+ let effectiveHeight = parsedHeight;
389
+ if (effectiveHeight + parsedMarginBottom > 0.9 * viewportHeight) {
390
+ effectiveHeight = Math.max(100, 0.9 * viewportHeight - parsedMarginBottom);
352
391
  }
353
392
 
354
393
  // Only apply if there's an actual change
355
394
  if (parsedHeight !== this.height || parsedMarginBottom !== this.marginBottom) {
356
395
  this.height = parsedHeight;
357
396
  this.marginBottom = parsedMarginBottom;
358
- this.minimizedHeight = `${this.height * 0.3}px`;
359
397
 
360
- console.log(`Height updated to: ${this.height}px, marginBottom: ${this.marginBottom}px`);
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
+ }
361
402
 
362
- // Apply the updated height/marginBottom if not ContactForm
403
+ console.log(`Height updated to: ${this.height}px (clamped to ${effectiveHeight}px for display), marginBottom: ${this.marginBottom}px`);
404
+
405
+ // Apply the updated height/marginBottom
363
406
  if (this.mode !== 'ContactForm') {
364
407
  if (this.containerDiv.dataset.position === 'in-place') {
365
408
  // "in-place" uses full width, sets containerDiv height
366
- this.containerDiv.style.height = `${this.height}px`;
409
+ this.containerDiv.style.height = `${effectiveHeight}px`;
367
410
  if (this.iframe) {
368
- this.iframe.style.height = `${this.height}px`;
411
+ this.iframe.style.height = `${effectiveHeight}px`;
369
412
  }
370
413
  if (this.minimizedIframe) {
371
414
  this.minimizedIframe.style.height = this.minimizedHeight;
@@ -519,7 +562,6 @@
519
562
  }
520
563
 
521
564
  try {
522
- console.log('[EmbeddedChat] Calling userTokenProvider...');
523
565
  const userToken = await this.userTokenProvider();
524
566
 
525
567
  if (!userToken) {
@@ -527,8 +569,6 @@
527
569
  return;
528
570
  }
529
571
 
530
- console.log('[EmbeddedChat] Got user token, length:', userToken?.length || 0);
531
-
532
572
  if (this.iframe?.contentWindow) {
533
573
  console.log('[EmbeddedChat] Sending auth message to iframe with targetOrigin:', this.targetOrigin);
534
574
  this.iframe.contentWindow.postMessage({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "embeddedaichatux",
3
- "version": "2.0.0",
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": {