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.
Files changed (2) hide show
  1. package/EmbeddedChat.js +118 -73
  2. 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 = `${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;
@@ -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: ${this.width}px;
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('#embedded-chat');
119
- 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");
120
121
 
121
- // wait for the real <iframe> element to load
122
- await this.waitForIframeLoad(this.iframe);
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 (typeof e.data === "object" && e.data?.type === "requestAuth") {
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
- if (typeof e.data === "object" && (!e.data.chatId || e.data.chatId === this.chatId)) {
195
- 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
+ }
196
226
 
197
- if (e.data.type === "setMinimizeOnScroll" || e.data.minimizeOnScroll !== undefined) {
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
- if (e.data.locale) {
203
- updates.locale = e.data.locale;
204
- }
205
- if (e.data.width) {
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
- // Apply iframe updates in one go
219
- if (Object.keys(updates).length > 0) {
220
- this.applyIframeUpdates(updates);
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
- // Handle maximize/minimize
224
- if (e.data.message) {
225
- if (e.data.message === "minimize") {
226
- if (this.mode !== 'ContactForm') {
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
- // Handle conversationId update
239
- if (e.data.conversationId) {
240
- this.setConversationId(e.data.conversationId);
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 = Math.max(parsedWidth, 320);
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
- if (parsedHeight + parsedMarginBottom > 0.9 * viewportHeight) {
346
- 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);
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
- 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
+ }
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 if not ContactForm
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 = `${this.height}px`;
409
+ this.containerDiv.style.height = `${effectiveHeight}px`;
362
410
  if (this.iframe) {
363
- this.iframe.style.height = `${this.height}px`;
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.0.1",
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": {