embeddedaichatux 1.3.2 → 1.5.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 +149 -49
- package/package.json +1 -1
package/EmbeddedChat.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
class EmbeddedChat {
|
|
1
|
+
class EmbeddedChat {
|
|
3
2
|
constructor(containerDiv, chatId, options) {
|
|
4
3
|
if (!containerDiv) {
|
|
5
4
|
containerDiv = this.createChatContainer();
|
|
@@ -11,88 +10,187 @@ class EmbeddedChat {
|
|
|
11
10
|
this.locale = options.locale || 'en';
|
|
12
11
|
this.previewParam = this.isPreview ? "?isPreview=true" : "";
|
|
13
12
|
this.serverUrl = this.options.serverUrl || 'https://embedgpt.chat/';
|
|
14
|
-
this.
|
|
13
|
+
this.height = options.height || 600; // Default height
|
|
14
|
+
this.width = options.width || 320; // Default width
|
|
15
|
+
this.enableAnimation = options.enableAnimation !== false; // Default to true if not provided
|
|
16
|
+
this.minimizedHeight = `${this.height * 0.3}px`; // 30% of the full height
|
|
17
|
+
this.mouseInsideChat = false;
|
|
18
|
+
this.hasRefreshed = false; // Flag to prevent endless loop
|
|
19
|
+
|
|
20
|
+
// Determine transition styles
|
|
21
|
+
const transitionStyle = this.enableAnimation ? 'transition: height 0.3s ease, opacity 0.3s ease;' : '';
|
|
22
|
+
|
|
23
|
+
this.positionStyle = this.containerDiv.dataset.position === 'in-place' ?
|
|
24
|
+
`width:100%; height:${this.height}px; ${transitionStyle}` :
|
|
25
|
+
`position: fixed; right: 0; bottom: 0; width: ${this.width}px; height: ${this.height}px; z-index: 100000; ${transitionStyle}`;
|
|
15
26
|
this.mode = options.mode || 'Chat'; // default to 'chat' if mode isn't provided
|
|
27
|
+
this.minimizeOnScroll = false; // Default to false
|
|
16
28
|
if (this.mode === 'ContactForm') {
|
|
17
29
|
// Adjust position style for contact form if mode is 'ContactForm'
|
|
18
|
-
this.positionStyle =
|
|
19
|
-
this.containerDiv.style.height =
|
|
30
|
+
this.positionStyle = `width:100%; height:${this.height}px; ${transitionStyle}`;
|
|
31
|
+
this.containerDiv.style.height = `${this.height}px`;
|
|
20
32
|
}
|
|
33
|
+
|
|
34
|
+
this.conversationId = this.getStoredConversationId();
|
|
35
|
+
|
|
21
36
|
this.sessionInfo = options.sessionInfo || null;
|
|
22
37
|
this.init();
|
|
23
38
|
}
|
|
24
39
|
|
|
40
|
+
isSafari() {
|
|
41
|
+
var ua = navigator.userAgent.toLowerCase();
|
|
42
|
+
return ua.indexOf('safari') != -1 && ua.indexOf('chrome') == -1;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
getStoredConversationId() {
|
|
46
|
+
try {
|
|
47
|
+
return localStorage.getItem(`conversationId_${this.chatId}`);
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error('Error accessing localStorage:', error);
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
setStoredConversationId(conversationId) {
|
|
55
|
+
try {
|
|
56
|
+
localStorage.setItem(`conversationId_${this.chatId}`, conversationId);
|
|
57
|
+
} catch (error) {
|
|
58
|
+
console.error('Error accessing localStorage:', error);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
25
62
|
init() {
|
|
63
|
+
this.updateIframes();
|
|
64
|
+
this.addEventListeners();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
updateIframes() {
|
|
26
68
|
const cleanedServerUrl = this.serverUrl.endsWith('/') ? this.serverUrl.slice(0, -1) : this.serverUrl;
|
|
27
69
|
const baseIframeUrl = `${cleanedServerUrl}/ChatUX/${this.chatId}`;
|
|
28
|
-
const minimizedPositionStyle =
|
|
70
|
+
const minimizedPositionStyle = `position: fixed; right: 0; bottom: 0; width: ${this.width}px; height: ${this.minimizedHeight}; z-index: 100000; ${this.enableAnimation ? 'transition: height 0.3s ease, opacity 0.3s ease;' : ''}`;
|
|
29
71
|
|
|
30
72
|
const iframeHtml = `
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
73
|
+
<iframe id="embedded-chat" style="${this.positionStyle}; display: none; border:none; overflow:hidden;" frameborder="0" sandbox="allow-same-origin allow-scripts allow-popups allow-forms allow-top-navigation-by-user-activation" src="${this.buildIframeUrl(baseIframeUrl, { isPreview: this.isPreview, mode: this.mode, locale: this.locale, conversationId: this.conversationId })}"></iframe>
|
|
74
|
+
<iframe id="embedded-chat-minimized" style="${minimizedPositionStyle}; display: none; border:none; overflow:hidden;" frameborder="0" sandbox="allow-same-origin allow-scripts allow-popups allow-forms" src="${this.buildIframeUrl(baseIframeUrl, { isPreview: this.isPreview, isMinimized: true, locale: this.locale, conversationId: this.conversationId })}"></iframe>
|
|
75
|
+
`;
|
|
34
76
|
|
|
35
77
|
this.containerDiv.innerHTML = iframeHtml;
|
|
36
78
|
this.iframe = this.containerDiv.querySelector("#embedded-chat");
|
|
37
79
|
this.minimizedIframe = this.containerDiv.querySelector("#embedded-chat-minimized");
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
addEventListeners() {
|
|
83
|
+
// Add event listeners to track mouse position
|
|
84
|
+
this.iframe.addEventListener("mouseenter", () => { this.mouseInsideChat = true; });
|
|
85
|
+
this.iframe.addEventListener("mouseleave", () => { this.mouseInsideChat = false; });
|
|
86
|
+
this.minimizedIframe.addEventListener("mouseenter", () => { this.mouseInsideChat = true; });
|
|
87
|
+
this.minimizedIframe.addEventListener("mouseleave", () => { this.mouseInsideChat = false; });
|
|
38
88
|
|
|
39
89
|
window.addEventListener("message", (e) => {
|
|
40
|
-
|
|
41
|
-
|
|
90
|
+
this.handleMessage(e);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
window.addEventListener("scroll", () => {
|
|
94
|
+
if (this.minimizeOnScroll && !this.mouseInsideChat) {
|
|
95
|
+
this.minimizeOnScrollAction();
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
handleMessage(e) {
|
|
101
|
+
if (typeof e.data === "object" && (!e.data.chatId || e.data.chatId === this.chatId)) {
|
|
102
|
+
if (e.data.type === "setMinimizeOnScroll") {
|
|
103
|
+
this.minimizeOnScroll = e.data.value === "true";
|
|
104
|
+
}
|
|
105
|
+
if (e.data.message) {
|
|
42
106
|
if (e.data.message === "minimize") {
|
|
43
107
|
if (this.mode !== 'ContactForm') {
|
|
44
|
-
|
|
45
|
-
this.iframe.style.display = "none";
|
|
46
|
-
this.minimizedIframe.style.display = "block";
|
|
108
|
+
this.animateMinimize();
|
|
47
109
|
}
|
|
48
110
|
} else if (e.data.message === "show" || e.data.message === "maximize") {
|
|
49
|
-
this.
|
|
50
|
-
this.minimizedIframe.style.display = "none";
|
|
51
|
-
// Check if the data has a scale property
|
|
52
|
-
if (e.data.scale) {
|
|
53
|
-
if (this.mode !== 'ContactForm') {
|
|
54
|
-
// No scaling support for ContactForm
|
|
55
|
-
|
|
56
|
-
// Resize the iframe according to the scale factor
|
|
57
|
-
this.iframe.style.transform = `scale(${e.data.scale})`;
|
|
58
|
-
this.iframe.style.transformOrigin = "bottom right";
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
// Send sessionInfo if available
|
|
62
|
-
if (this.sessionInfo !== null) {
|
|
63
|
-
this.setSessionInfo(this.sessionInfo);
|
|
64
|
-
}
|
|
111
|
+
this.showMaximized();
|
|
65
112
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (
|
|
70
|
-
this.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
this.
|
|
74
|
-
this.
|
|
113
|
+
if (e.data.scale) {
|
|
114
|
+
this.applyScale(e.data.scale);
|
|
115
|
+
}
|
|
116
|
+
if (this.sessionInfo !== null) {
|
|
117
|
+
this.setSessionInfo(this.sessionInfo);
|
|
118
|
+
}
|
|
119
|
+
if (e.data.message === "show" && e.data.conversationId) {
|
|
120
|
+
this.conversationId = e.data.conversationId;
|
|
121
|
+
this.setStoredConversationId(this.conversationId);
|
|
75
122
|
}
|
|
76
123
|
}
|
|
77
|
-
})
|
|
124
|
+
} else if (typeof e.data === "string") {
|
|
125
|
+
if (e.data === "minimize") {
|
|
126
|
+
this.animateMinimize();
|
|
127
|
+
} else if (e.data === "show" || e.data === "maximize") {
|
|
128
|
+
this.showMaximized();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
animateMinimize() {
|
|
134
|
+
if (this.mode !== 'ContactForm') {
|
|
135
|
+
this.iframe.style.height = this.minimizedHeight;
|
|
136
|
+
this.iframe.style.opacity = '0'; // Full transparency at the end
|
|
137
|
+
setTimeout(() => {
|
|
138
|
+
this.iframe.style.display = "none";
|
|
139
|
+
this.iframe.style.opacity = '1'; // Reset opacity to 1 for next time
|
|
140
|
+
this.minimizedIframe.style.display = "block";
|
|
141
|
+
this.minimizedIframe.style.height = this.minimizedHeight;
|
|
142
|
+
this.minimizedIframe.style.opacity = '1'; // Reset opacity to 1
|
|
143
|
+
}, this.enableAnimation ? 300 : 0); // Match the transition duration
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
showMaximized() {
|
|
148
|
+
this.minimizedIframe.style.display = "none";
|
|
149
|
+
|
|
150
|
+
this.minimizedIframe.style.height = `${this.height}px`;
|
|
151
|
+
this.minimizedIframe.style.opacity = ''; // Reset opacity to unset
|
|
152
|
+
|
|
153
|
+
this.iframe.style.display = "block";
|
|
154
|
+
|
|
155
|
+
if (this.isSafari() && !this.hasRefreshed) {
|
|
156
|
+
// Force refresh by resetting the iframe's src
|
|
157
|
+
const currentSrc = this.iframe.src;
|
|
158
|
+
this.iframe.src = ''; // Temporarily clear the src
|
|
159
|
+
this.iframe.src = currentSrc; // Reset to the original src to trigger a reload
|
|
160
|
+
this.hasRefreshed = true; // Prevent endless loop
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
this.iframe.style.height = `${this.height}px`;
|
|
164
|
+
this.iframe.style.opacity = '1';
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
applyScale(scale) {
|
|
168
|
+
if (this.mode !== 'ContactForm') {
|
|
169
|
+
this.iframe.style.transform = `scale(${scale})`;
|
|
170
|
+
this.iframe.style.transformOrigin = "bottom right";
|
|
171
|
+
this.minimizedIframe.style.transform = `scale(${scale})`;
|
|
172
|
+
this.minimizedIframe.style.transformOrigin = "bottom right";
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
minimizeOnScrollAction() {
|
|
177
|
+
if (this.mode !== 'ContactForm' && this.iframe.style.display !== "none") {
|
|
178
|
+
this.animateMinimize();
|
|
179
|
+
}
|
|
78
180
|
}
|
|
79
181
|
|
|
80
182
|
setSessionInfo(sessionInfo) {
|
|
81
183
|
console.log('setSessionInfo called with sessionInfo:', sessionInfo);
|
|
82
184
|
|
|
83
|
-
// Store the new sessionInfo
|
|
84
185
|
this.sessionInfo = sessionInfo;
|
|
85
186
|
|
|
86
|
-
// Obtain the iframe element
|
|
87
187
|
const iframe = this.containerDiv.querySelector("#embedded-chat");
|
|
88
188
|
|
|
89
|
-
// Function to post the message with a structured object
|
|
90
189
|
const postMessage = () => {
|
|
91
190
|
console.log('Posting message to iframe:', { type: 'setSessionInfo', sessionInfo: sessionInfo });
|
|
92
191
|
iframe.contentWindow.postMessage({ type: 'setSessionInfo', sessionInfo: sessionInfo }, "*");
|
|
93
192
|
};
|
|
94
193
|
|
|
95
|
-
// If the iframe is visible, post the message
|
|
96
194
|
if (iframe.style.display !== "none") {
|
|
97
195
|
postMessage();
|
|
98
196
|
}
|
|
@@ -107,9 +205,8 @@ class EmbeddedChat {
|
|
|
107
205
|
}
|
|
108
206
|
|
|
109
207
|
buildIframeUrl(baseIframeUrl, params = {}) {
|
|
110
|
-
const urlParams = new URLSearchParams(
|
|
208
|
+
const urlParams = new URLSearchParams();
|
|
111
209
|
|
|
112
|
-
// Add parameters as needed, based on values in the params object
|
|
113
210
|
if (params.isPreview) {
|
|
114
211
|
urlParams.set('isPreview', 'true');
|
|
115
212
|
}
|
|
@@ -122,9 +219,12 @@ class EmbeddedChat {
|
|
|
122
219
|
urlParams.set('locale', params.locale);
|
|
123
220
|
}
|
|
124
221
|
|
|
125
|
-
|
|
222
|
+
if (params.conversationId) {
|
|
223
|
+
urlParams.set('conversationId', params.conversationId);
|
|
224
|
+
}
|
|
225
|
+
|
|
126
226
|
for (const [key, value] of Object.entries(params)) {
|
|
127
|
-
if (key !== 'mode' && key !== 'isPreview'
|
|
227
|
+
if (key !== 'mode' && key !== 'isPreview' && key !== 'conversationId' && value !== null && value !== undefined) {
|
|
128
228
|
urlParams.set(key, value);
|
|
129
229
|
}
|
|
130
230
|
}
|
|
@@ -138,6 +238,6 @@ export function initEmbeddedChat(containerDiv, chatId, options) {
|
|
|
138
238
|
}
|
|
139
239
|
|
|
140
240
|
export function initContactForm(containerDiv, chatId, options) {
|
|
141
|
-
const clonedOptions = { ...options, mode: 'ContactForm' };
|
|
241
|
+
const clonedOptions = { ...options, mode: 'ContactForm' };
|
|
142
242
|
return new EmbeddedChat(containerDiv, chatId, clonedOptions);
|
|
143
243
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "embeddedaichatux",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.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": {
|