open-chat-studio-widget 0.4.7 → 0.5.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/README.md +23 -20
- package/dist/cjs/app-globals-V2Kpy_OQ.js +8 -0
- package/dist/cjs/app-globals-V2Kpy_OQ.js.map +1 -0
- package/dist/cjs/{index-c9203be6.js → index-CC3Krx2K.js} +331 -238
- package/dist/cjs/index-CC3Krx2K.js.map +1 -0
- package/dist/cjs/index.cjs.js +1 -0
- package/dist/cjs/index.cjs.js.map +1 -1
- package/dist/cjs/loader.cjs.js +4 -5
- package/dist/cjs/loader.cjs.js.map +1 -1
- package/dist/cjs/open-chat-studio-widget.cjs.entry.js +5124 -4272
- package/dist/cjs/open-chat-studio-widget.cjs.entry.js.map +1 -1
- package/dist/cjs/open-chat-studio-widget.cjs.js +8 -7
- package/dist/cjs/open-chat-studio-widget.cjs.js.map +1 -1
- package/dist/cjs/open-chat-studio-widget.entry.cjs.js.map +1 -0
- package/dist/collection/collection-manifest.json +1 -1
- package/dist/collection/components/ocs-chat/{heroicons.js → icons.js} +23 -1
- package/dist/collection/components/ocs-chat/icons.js.map +1 -0
- package/dist/collection/components/ocs-chat/ocs-chat.css +596 -1947
- package/dist/collection/components/ocs-chat/ocs-chat.js +521 -293
- package/dist/collection/components/ocs-chat/ocs-chat.js.map +1 -1
- package/dist/collection/services/chat-session-service.js +145 -0
- package/dist/collection/services/chat-session-service.js.map +1 -0
- package/dist/collection/services/file-attachment-manager.js +125 -0
- package/dist/collection/services/file-attachment-manager.js.map +1 -0
- package/dist/collection/utils/cookies.js +5 -12
- package/dist/collection/utils/cookies.js.map +1 -1
- package/dist/collection/utils/markdown.js +1 -1
- package/dist/collection/utils/markdown.js.map +1 -1
- package/dist/collection/utils/translations.js +99 -0
- package/dist/collection/utils/translations.js.map +1 -0
- package/dist/components/index.js +2 -1
- package/dist/components/open-chat-studio-widget.js +5125 -4266
- package/dist/components/open-chat-studio-widget.js.map +1 -1
- package/dist/esm/app-globals-DQuL1Twl.js +6 -0
- package/dist/esm/app-globals-DQuL1Twl.js.map +1 -0
- package/dist/esm/{index-0349ca51.js → index-BF7CYZiN.js} +329 -217
- package/dist/esm/index-BF7CYZiN.js.map +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/loader.js +5 -4
- package/dist/esm/loader.js.map +1 -1
- package/dist/esm/open-chat-studio-widget.entry.js +5125 -4271
- package/dist/esm/open-chat-studio-widget.entry.js.map +1 -1
- package/dist/esm/open-chat-studio-widget.js +7 -5
- package/dist/esm/open-chat-studio-widget.js.map +1 -1
- package/dist/open-chat-studio-widget/index.esm.js.map +1 -1
- package/dist/open-chat-studio-widget/loader.esm.js.map +1 -0
- package/dist/open-chat-studio-widget/open-chat-studio-widget.entry.esm.js.map +1 -0
- package/dist/open-chat-studio-widget/open-chat-studio-widget.esm.js +1 -1
- package/dist/open-chat-studio-widget/open-chat-studio-widget.esm.js.map +1 -1
- package/dist/open-chat-studio-widget/p-400b1f47.entry.js +4 -0
- package/dist/open-chat-studio-widget/p-400b1f47.entry.js.map +1 -0
- package/dist/open-chat-studio-widget/p-BF7CYZiN.js +3 -0
- package/dist/open-chat-studio-widget/p-BF7CYZiN.js.map +1 -0
- package/dist/open-chat-studio-widget/p-DQuL1Twl.js +2 -0
- package/dist/open-chat-studio-widget/p-DQuL1Twl.js.map +1 -0
- package/dist/types/components/ocs-chat/{heroicons.d.ts → icons.d.ts} +19 -0
- package/dist/types/components/ocs-chat/ocs-chat.d.ts +57 -36
- package/dist/types/components.d.ts +36 -2
- package/dist/types/services/chat-session-service.d.ts +78 -0
- package/dist/types/services/file-attachment-manager.d.ts +40 -0
- package/dist/types/stencil-public-runtime.d.ts +35 -6
- package/dist/types/utils/translations.d.ts +23 -0
- package/package.json +9 -4
- package/dist/cjs/app-globals-3a1e7e63.js +0 -7
- package/dist/cjs/app-globals-3a1e7e63.js.map +0 -1
- package/dist/cjs/index-c9203be6.js.map +0 -1
- package/dist/collection/components/ocs-chat/heroicons.js.map +0 -1
- package/dist/esm/app-globals-0f993ce5.js +0 -5
- package/dist/esm/app-globals-0f993ce5.js.map +0 -1
- package/dist/esm/index-0349ca51.js.map +0 -1
- package/dist/open-chat-studio-widget/p-3dc66a9a.js +0 -3
- package/dist/open-chat-studio-widget/p-3dc66a9a.js.map +0 -1
- package/dist/open-chat-studio-widget/p-6b9a332c.entry.js +0 -4
- package/dist/open-chat-studio-widget/p-6b9a332c.entry.js.map +0 -1
- package/dist/open-chat-studio-widget/p-e1255160.js +0 -2
- package/dist/open-chat-studio-widget/p-e1255160.js.map +0 -1
- package/loader/package.json +0 -11
|
@@ -1,23 +1,21 @@
|
|
|
1
1
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2
|
-
import { Host, h } from "@stencil/core";
|
|
3
|
-
import { XMarkIcon, GripDotsVerticalIcon, PlusWithCircleIcon, ArrowsPointingOutIcon, ArrowsPointingInIcon, PaperClipIcon, CheckDocumentIcon, XIcon } from "./
|
|
2
|
+
import { Host, h, Env } from "@stencil/core";
|
|
3
|
+
import { XMarkIcon, GripDotsVerticalIcon, PlusWithCircleIcon, ArrowsPointingOutIcon, ArrowsPointingInIcon, PaperClipIcon, CheckDocumentIcon, XIcon, OcsWidgetAvatar } from "./icons";
|
|
4
4
|
import { renderMarkdownSync as renderMarkdownComplete } from "../../utils/markdown";
|
|
5
|
-
import { getCSRFToken } from "../../utils/cookies";
|
|
6
5
|
import { varToPixels } from "../../utils/utils";
|
|
6
|
+
import { TranslationManager, defaultTranslations } from "../../utils/translations";
|
|
7
|
+
import { ChatSessionService } from "../../services/chat-session-service";
|
|
8
|
+
import { FileAttachmentManager } from "../../services/file-attachment-manager";
|
|
7
9
|
export class OcsChat {
|
|
8
10
|
constructor() {
|
|
9
11
|
/**
|
|
10
|
-
* The base URL for the API
|
|
12
|
+
* The base URL for the API.
|
|
11
13
|
*/
|
|
12
|
-
this.apiBaseUrl = "https://
|
|
14
|
+
this.apiBaseUrl = "https://www.openchatstudio.com";
|
|
13
15
|
/**
|
|
14
16
|
* The shape of the chat button. 'round' makes it circular, 'square' keeps it rectangular.
|
|
15
17
|
*/
|
|
16
18
|
this.buttonShape = 'square';
|
|
17
|
-
/**
|
|
18
|
-
* The message to display in the new chat confirmation dialog.
|
|
19
|
-
*/
|
|
20
|
-
this.newChatConfirmationMessage = "Starting a new chat will clear your current conversation. Continue?";
|
|
21
19
|
/**
|
|
22
20
|
* Whether the chat widget is visible on load.
|
|
23
21
|
*/
|
|
@@ -43,10 +41,6 @@ export class OcsChat {
|
|
|
43
41
|
* Allow the user to attach files to their messages.
|
|
44
42
|
*/
|
|
45
43
|
this.allowAttachments = false;
|
|
46
|
-
/**
|
|
47
|
-
* The text to display while the assistant is typing/preparing a response.
|
|
48
|
-
*/
|
|
49
|
-
this.typingIndicatorText = "Preparing response";
|
|
50
44
|
this.error = "";
|
|
51
45
|
this.messages = [];
|
|
52
46
|
this.isLoading = false;
|
|
@@ -63,6 +57,20 @@ export class OcsChat {
|
|
|
63
57
|
this.showNewChatConfirmation = false;
|
|
64
58
|
this.selectedFiles = [];
|
|
65
59
|
this.isUploadingFiles = false;
|
|
60
|
+
this.buttonPosition = { x: 30, y: 30 };
|
|
61
|
+
this.buttonHorizontalSide = 'right';
|
|
62
|
+
this.buttonVerticalSide = 'bottom';
|
|
63
|
+
this.isButtonDragging = false;
|
|
64
|
+
this.buttonWasDragged = false;
|
|
65
|
+
this.translationManager = new TranslationManager();
|
|
66
|
+
this.attachmentManager = new FileAttachmentManager({
|
|
67
|
+
supportedExtensions: OcsChat.SUPPORTED_FILE_EXTENSIONS,
|
|
68
|
+
maxFileSizeMb: OcsChat.MAX_FILE_SIZE_MB,
|
|
69
|
+
maxTotalSizeMb: OcsChat.MAX_TOTAL_SIZE_MB,
|
|
70
|
+
});
|
|
71
|
+
this.buttonDragOffset = { x: 0, y: 0 };
|
|
72
|
+
this.rafId = null;
|
|
73
|
+
this.buttonListenersAttached = false;
|
|
66
74
|
this.chatWindowHeight = 600;
|
|
67
75
|
this.chatWindowWidth = 450;
|
|
68
76
|
this.chatWindowFullscreenWidth = 1024;
|
|
@@ -111,15 +119,101 @@ export class OcsChat {
|
|
|
111
119
|
this.endDrag();
|
|
112
120
|
};
|
|
113
121
|
this.handleWindowResize = () => {
|
|
122
|
+
var _a, _b;
|
|
114
123
|
this.positionInitialized = false;
|
|
115
124
|
this.initializePosition();
|
|
125
|
+
// Revalidate button position after resize to keep it within viewport bounds
|
|
126
|
+
if (this.isButtonDraggable()) {
|
|
127
|
+
const windowWidth = window.innerWidth;
|
|
128
|
+
const windowHeight = window.innerHeight;
|
|
129
|
+
const buttonWidth = ((_a = this.buttonRef) === null || _a === void 0 ? void 0 : _a.offsetWidth) || 60;
|
|
130
|
+
const buttonHeight = ((_b = this.buttonRef) === null || _b === void 0 ? void 0 : _b.offsetHeight) || 60;
|
|
131
|
+
const minPadding = 10;
|
|
132
|
+
this.buttonPosition = {
|
|
133
|
+
x: Math.max(minPadding, Math.min(this.buttonPosition.x, windowWidth - buttonWidth - minPadding)),
|
|
134
|
+
y: Math.max(minPadding, Math.min(this.buttonPosition.y, windowHeight - buttonHeight - minPadding))
|
|
135
|
+
};
|
|
136
|
+
this.updateHostPosition();
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
this.handleButtonMouseDown = (event) => {
|
|
140
|
+
if (!this.buttonRef || !this.isButtonDraggable())
|
|
141
|
+
return;
|
|
142
|
+
event.preventDefault();
|
|
143
|
+
event.stopPropagation();
|
|
144
|
+
const pointer = this.getPointerCoordinates(event);
|
|
145
|
+
if (!pointer)
|
|
146
|
+
return;
|
|
147
|
+
this.isButtonDragging = true;
|
|
148
|
+
this.buttonWasDragged = false; // Reset the drag flag
|
|
149
|
+
const rect = this.host.getBoundingClientRect();
|
|
150
|
+
this.buttonDragOffset = {
|
|
151
|
+
x: pointer.clientX - rect.left,
|
|
152
|
+
y: pointer.clientY - rect.top
|
|
153
|
+
};
|
|
154
|
+
this.addButtonEventListeners();
|
|
155
|
+
};
|
|
156
|
+
this.handleButtonTouchStart = (event) => {
|
|
157
|
+
if (!this.buttonRef || !this.isButtonDraggable())
|
|
158
|
+
return;
|
|
159
|
+
event.preventDefault();
|
|
160
|
+
event.stopPropagation();
|
|
161
|
+
const pointer = this.getPointerCoordinates(event);
|
|
162
|
+
if (!pointer)
|
|
163
|
+
return;
|
|
164
|
+
this.isButtonDragging = true;
|
|
165
|
+
this.buttonWasDragged = false; // Reset the drag flag
|
|
166
|
+
const rect = this.host.getBoundingClientRect();
|
|
167
|
+
this.buttonDragOffset = {
|
|
168
|
+
x: pointer.clientX - rect.left,
|
|
169
|
+
y: pointer.clientY - rect.top
|
|
170
|
+
};
|
|
171
|
+
this.addButtonEventListeners();
|
|
172
|
+
};
|
|
173
|
+
this.handleButtonMouseMove = (event) => {
|
|
174
|
+
if (!this.isButtonDragging)
|
|
175
|
+
return;
|
|
176
|
+
const pointer = this.getPointerCoordinates(event);
|
|
177
|
+
if (!pointer)
|
|
178
|
+
return;
|
|
179
|
+
this.updateButtonPosition(pointer);
|
|
180
|
+
};
|
|
181
|
+
this.handleButtonTouchMove = (event) => {
|
|
182
|
+
if (!this.isButtonDragging)
|
|
183
|
+
return;
|
|
184
|
+
event.preventDefault();
|
|
185
|
+
const pointer = this.getPointerCoordinates(event);
|
|
186
|
+
if (!pointer)
|
|
187
|
+
return;
|
|
188
|
+
this.updateButtonPosition(pointer);
|
|
189
|
+
};
|
|
190
|
+
this.handleButtonMouseUp = () => {
|
|
191
|
+
if (this.isButtonDragging) {
|
|
192
|
+
this.isButtonDragging = false;
|
|
193
|
+
this.removeButtonEventListeners();
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
this.handleButtonTouchEnd = () => {
|
|
197
|
+
if (this.isButtonDragging) {
|
|
198
|
+
this.isButtonDragging = false;
|
|
199
|
+
this.removeButtonEventListeners();
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
this.handleButtonClick = () => {
|
|
203
|
+
// Only toggle visibility if the button wasn't dragged
|
|
204
|
+
if (!this.buttonWasDragged) {
|
|
205
|
+
this.toggleWindowVisibility();
|
|
206
|
+
}
|
|
207
|
+
// Reset the flag after handling the click
|
|
208
|
+
this.buttonWasDragged = false;
|
|
116
209
|
};
|
|
117
210
|
}
|
|
118
|
-
componentWillLoad() {
|
|
211
|
+
async componentWillLoad() {
|
|
119
212
|
if (!this.chatbotId) {
|
|
120
213
|
this.error = 'Chatbot ID is required';
|
|
121
214
|
return;
|
|
122
215
|
}
|
|
216
|
+
await this.initializeTranslations();
|
|
123
217
|
// Always try to load existing session if localStorage is available
|
|
124
218
|
if (this.persistentSession && this.isLocalStorageAvailable()) {
|
|
125
219
|
const { sessionId, messages } = this.loadSessionFromStorage();
|
|
@@ -139,6 +233,8 @@ export class OcsChat {
|
|
|
139
233
|
this.chatWindowHeight = varToPixels(windowHeightVar, window.innerHeight, this.chatWindowHeight);
|
|
140
234
|
this.chatWindowWidth = varToPixels(windowWidthVar, window.innerWidth, this.chatWindowWidth);
|
|
141
235
|
this.chatWindowFullscreenWidth = varToPixels(fullscreenWidthVar, window.innerWidth, this.chatWindowFullscreenWidth);
|
|
236
|
+
// Initialize button position from computed styles
|
|
237
|
+
this.initializeButtonPosition();
|
|
142
238
|
if (this.visible) {
|
|
143
239
|
this.initializePosition();
|
|
144
240
|
}
|
|
@@ -148,15 +244,29 @@ export class OcsChat {
|
|
|
148
244
|
}
|
|
149
245
|
else if (this.visible && this.sessionId) {
|
|
150
246
|
// Resume polling for existing session
|
|
151
|
-
this.
|
|
247
|
+
this.startMessagePolling();
|
|
152
248
|
}
|
|
153
249
|
window.addEventListener('resize', this.handleWindowResize);
|
|
154
250
|
}
|
|
155
251
|
disconnectedCallback() {
|
|
156
252
|
this.cleanup();
|
|
157
253
|
this.removeEventListeners();
|
|
254
|
+
this.removeButtonEventListeners();
|
|
158
255
|
window.removeEventListener('resize', this.handleWindowResize);
|
|
159
256
|
}
|
|
257
|
+
getChatService() {
|
|
258
|
+
if (!this.chatService) {
|
|
259
|
+
this.chatService = new ChatSessionService({
|
|
260
|
+
apiBaseUrl: this.apiBaseUrl || 'https://www.openchatstudio.com',
|
|
261
|
+
embedKey: this.embedKey,
|
|
262
|
+
widgetVersion: Env.version,
|
|
263
|
+
taskPollingIntervalMs: OcsChat.TASK_POLLING_INTERVAL_MS,
|
|
264
|
+
taskPollingMaxAttempts: OcsChat.TASK_POLLING_MAX_ATTEMPTS,
|
|
265
|
+
messagePollingIntervalMs: OcsChat.MESSAGE_POLLING_INTERVAL_MS,
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
return this.chatService;
|
|
269
|
+
}
|
|
160
270
|
addErrorMessage(errorText) {
|
|
161
271
|
const errorMessage = {
|
|
162
272
|
created_at: new Date().toISOString(),
|
|
@@ -200,25 +310,34 @@ export class OcsChat {
|
|
|
200
310
|
parseStarterQuestions() {
|
|
201
311
|
this.parsedStarterQuestions = this.parseJSONProp(this.starterQuestions, 'starter questions');
|
|
202
312
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
313
|
+
async initializeTranslations() {
|
|
314
|
+
let customTranslationsObj;
|
|
315
|
+
if (this.translationsUrl) {
|
|
316
|
+
customTranslationsObj = await this.loadTranslationsFromUrl(this.translationsUrl);
|
|
207
317
|
}
|
|
208
|
-
this.
|
|
318
|
+
this.translationManager = new TranslationManager(this.language, customTranslationsObj);
|
|
209
319
|
}
|
|
210
|
-
|
|
211
|
-
|
|
320
|
+
async loadTranslationsFromUrl(url) {
|
|
321
|
+
try {
|
|
322
|
+
const response = await fetch(url);
|
|
323
|
+
if (!response.ok) {
|
|
324
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
325
|
+
}
|
|
326
|
+
const translations = await response.json();
|
|
327
|
+
return translations;
|
|
328
|
+
}
|
|
329
|
+
catch (error) {
|
|
330
|
+
console.error('Error loading translations from URL:', error);
|
|
331
|
+
return defaultTranslations;
|
|
332
|
+
}
|
|
212
333
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
if (csrfToken) {
|
|
219
|
-
headers['X-CSRFToken'] = csrfToken;
|
|
334
|
+
cleanup() {
|
|
335
|
+
this.stopMessagePolling();
|
|
336
|
+
if (this.taskPollingHandle) {
|
|
337
|
+
this.taskPollingHandle.cancel();
|
|
338
|
+
this.taskPollingHandle = undefined;
|
|
220
339
|
}
|
|
221
|
-
|
|
340
|
+
this.currentPollTaskId = '';
|
|
222
341
|
}
|
|
223
342
|
async startSession() {
|
|
224
343
|
try {
|
|
@@ -235,94 +354,38 @@ export class OcsChat {
|
|
|
235
354
|
if (this.userName) {
|
|
236
355
|
requestBody.participant_name = this.userName;
|
|
237
356
|
}
|
|
238
|
-
const
|
|
239
|
-
method: 'POST',
|
|
240
|
-
headers: this.getApiHeaders(),
|
|
241
|
-
body: JSON.stringify(requestBody)
|
|
242
|
-
});
|
|
243
|
-
if (!response.ok) {
|
|
244
|
-
this.handleError(`Failed to start session: ${response.statusText}`);
|
|
245
|
-
return;
|
|
246
|
-
}
|
|
247
|
-
const data = await response.json();
|
|
357
|
+
const data = await this.getChatService().startSession(requestBody);
|
|
248
358
|
this.sessionId = data.session_id;
|
|
249
359
|
this.saveSessionToStorage();
|
|
250
360
|
// Handle seed message if present
|
|
251
361
|
if (data.seed_message_task_id) {
|
|
252
|
-
this.
|
|
253
|
-
|
|
254
|
-
|
|
362
|
+
this.startTaskPolling(data.seed_message_task_id);
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
this.startMessagePolling();
|
|
255
366
|
}
|
|
256
|
-
// Start polling for messages
|
|
257
|
-
this.startPolling();
|
|
258
367
|
}
|
|
259
|
-
catch (
|
|
368
|
+
catch (_error) {
|
|
260
369
|
this.handleError('Failed to start chat session');
|
|
261
370
|
}
|
|
262
371
|
finally {
|
|
263
372
|
this.isLoading = false;
|
|
264
373
|
}
|
|
265
374
|
}
|
|
266
|
-
markPendingFilesWithError(errorMessage) {
|
|
267
|
-
this.selectedFiles = this.selectedFiles.map(sf => {
|
|
268
|
-
if (!sf.error && !sf.uploaded) {
|
|
269
|
-
return Object.assign(Object.assign({}, sf), { error: errorMessage });
|
|
270
|
-
}
|
|
271
|
-
return sf;
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
375
|
async uploadFiles() {
|
|
275
376
|
if (this.selectedFiles.length === 0 || !this.sessionId || !this.allowAttachments) {
|
|
276
377
|
return [];
|
|
277
378
|
}
|
|
278
379
|
this.isUploadingFiles = true;
|
|
279
|
-
const uploadedIds = [];
|
|
280
380
|
try {
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
// Add user ID and name to the form data
|
|
292
|
-
const userId = this.getOrGenerateUserId();
|
|
293
|
-
formData.append('participant_remote_id', userId);
|
|
294
|
-
if (this.userName) {
|
|
295
|
-
formData.append('participant_name', this.userName);
|
|
296
|
-
}
|
|
297
|
-
// Only upload if there are new files
|
|
298
|
-
if (formData.has('files')) {
|
|
299
|
-
const response = await fetch(`${this.getApiBaseUrl()}/api/chat/${this.sessionId}/upload/`, {
|
|
300
|
-
method: 'POST',
|
|
301
|
-
body: formData,
|
|
302
|
-
});
|
|
303
|
-
if (!response.ok) {
|
|
304
|
-
const errorData = await response.json();
|
|
305
|
-
const errorMessage = errorData.error || 'Failed to upload files';
|
|
306
|
-
this.markPendingFilesWithError(errorMessage);
|
|
307
|
-
return uploadedIds;
|
|
308
|
-
}
|
|
309
|
-
const data = await response.json();
|
|
310
|
-
// Update selected files with upload results
|
|
311
|
-
let fileIndex = 0;
|
|
312
|
-
this.selectedFiles = this.selectedFiles.map(sf => {
|
|
313
|
-
if (!sf.error && !sf.uploaded) {
|
|
314
|
-
return Object.assign(Object.assign({}, sf), { uploaded: data.files[fileIndex++] });
|
|
315
|
-
}
|
|
316
|
-
return sf;
|
|
317
|
-
});
|
|
318
|
-
uploadedIds.push(...data.files.map((f) => f.id));
|
|
319
|
-
}
|
|
320
|
-
return uploadedIds;
|
|
321
|
-
}
|
|
322
|
-
catch (error) {
|
|
323
|
-
const errorMessage = error instanceof Error ? error.message : 'Failed to upload files';
|
|
324
|
-
this.markPendingFilesWithError(errorMessage);
|
|
325
|
-
return uploadedIds;
|
|
381
|
+
const uploadResult = await this.attachmentManager.uploadPendingFiles(this.selectedFiles, {
|
|
382
|
+
apiBaseUrl: this.apiBaseUrl || 'https://www.openchatstudio.com',
|
|
383
|
+
sessionId: this.sessionId,
|
|
384
|
+
participantId: this.getOrGenerateUserId(),
|
|
385
|
+
participantName: this.userName,
|
|
386
|
+
});
|
|
387
|
+
this.selectedFiles = uploadResult.selectedFiles;
|
|
388
|
+
return uploadResult.uploadedIds;
|
|
326
389
|
}
|
|
327
390
|
finally {
|
|
328
391
|
this.isUploadingFiles = false;
|
|
@@ -375,27 +438,15 @@ export class OcsChat {
|
|
|
375
438
|
this.selectedFiles = []; // Clear selected files after sending
|
|
376
439
|
}
|
|
377
440
|
this.scrollToBottom();
|
|
378
|
-
// Start typing indicator - it will stay on during task polling
|
|
379
|
-
this.isTyping = true;
|
|
380
441
|
const requestBody = { message: message.trim() };
|
|
381
442
|
if (this.allowAttachments && attachmentIds.length > 0) {
|
|
382
443
|
requestBody.attachment_ids = attachmentIds;
|
|
383
444
|
}
|
|
384
|
-
const
|
|
385
|
-
method: 'POST',
|
|
386
|
-
headers: this.getApiHeaders(),
|
|
387
|
-
body: JSON.stringify(requestBody)
|
|
388
|
-
});
|
|
389
|
-
if (!response.ok) {
|
|
390
|
-
throw new Error(`Failed to send message: ${response.statusText}`);
|
|
391
|
-
}
|
|
392
|
-
const data = await response.json();
|
|
445
|
+
const data = await this.getChatService().sendMessage(this.sessionId, requestBody);
|
|
393
446
|
if (data.status === 'error') {
|
|
394
447
|
throw new Error(data.error || 'Failed to send message');
|
|
395
448
|
}
|
|
396
|
-
|
|
397
|
-
this.currentPollTaskId = data.task_id;
|
|
398
|
-
await this.pollTaskResponse();
|
|
449
|
+
this.startTaskPolling(data.task_id);
|
|
399
450
|
}
|
|
400
451
|
catch (error) {
|
|
401
452
|
const errorText = error instanceof Error ? error.message : 'Failed to send message';
|
|
@@ -405,114 +456,30 @@ export class OcsChat {
|
|
|
405
456
|
handleStarterQuestionClick(question) {
|
|
406
457
|
this.sendMessage(question);
|
|
407
458
|
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
const poll = async () => {
|
|
415
|
-
if (!this.sessionId || !this.currentPollTaskId)
|
|
416
|
-
return;
|
|
417
|
-
try {
|
|
418
|
-
const response = await fetch(`${this.getApiBaseUrl()}/api/chat/${this.sessionId}/${this.currentPollTaskId}/poll/`);
|
|
419
|
-
if (!response.ok) {
|
|
420
|
-
throw new Error(`Failed to poll task: ${response.statusText}`);
|
|
421
|
-
}
|
|
422
|
-
const data = await response.json();
|
|
423
|
-
if (data.error) {
|
|
424
|
-
throw new Error(data.error);
|
|
425
|
-
}
|
|
426
|
-
if (data.status === 'complete' && data.message) {
|
|
427
|
-
this.messages = [...this.messages, data.message];
|
|
428
|
-
this.saveSessionToStorage();
|
|
429
|
-
this.scrollToBottom();
|
|
430
|
-
// Task polling complete, clear typing indicator and resume message polling
|
|
431
|
-
this.isTyping = false;
|
|
432
|
-
this.currentPollTaskId = '';
|
|
433
|
-
this.resumeMessagePolling();
|
|
434
|
-
this.focusInput();
|
|
435
|
-
return;
|
|
436
|
-
}
|
|
437
|
-
if (data.status === 'processing' && attempts < OcsChat.TASK_POLLING_MAX_ATTEMPTS) {
|
|
438
|
-
attempts++;
|
|
439
|
-
setTimeout(poll, OcsChat.TASK_POLLING_INTERVAL_MS);
|
|
440
|
-
}
|
|
441
|
-
else if (attempts >= OcsChat.TASK_POLLING_MAX_ATTEMPTS) {
|
|
442
|
-
// Task polling timed out - add timeout message and resume polling
|
|
443
|
-
const timeoutMessage = {
|
|
444
|
-
created_at: new Date().toISOString(),
|
|
445
|
-
role: 'system',
|
|
446
|
-
content: 'The response is taking longer than expected. The system may be experiencing delays. Please try sending your message again.',
|
|
447
|
-
attachments: []
|
|
448
|
-
};
|
|
449
|
-
this.messages = [...this.messages, timeoutMessage];
|
|
450
|
-
this.saveSessionToStorage();
|
|
451
|
-
this.scrollToBottom();
|
|
452
|
-
// Clear typing indicator and resume message polling
|
|
453
|
-
this.isTyping = false;
|
|
454
|
-
this.currentPollTaskId = '';
|
|
455
|
-
this.resumeMessagePolling();
|
|
456
|
-
this.focusInput();
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
catch (error) {
|
|
460
|
-
const errorText = error instanceof Error ? error.message : 'Failed to get response';
|
|
461
|
-
this.handleError(errorText);
|
|
462
|
-
// Clear states and resume polling
|
|
463
|
-
this.currentPollTaskId = '';
|
|
464
|
-
this.resumeMessagePolling();
|
|
465
|
-
}
|
|
466
|
-
};
|
|
467
|
-
await poll();
|
|
468
|
-
}
|
|
469
|
-
startPolling() {
|
|
470
|
-
if (this.pollingIntervalRef)
|
|
471
|
-
return;
|
|
472
|
-
this.pollingIntervalRef = setInterval(async () => {
|
|
473
|
-
// Only poll for messages if not currently polling for a task
|
|
474
|
-
if (!this.currentPollTaskId) {
|
|
475
|
-
await this.pollForMessages();
|
|
476
|
-
}
|
|
477
|
-
}, OcsChat.MESSAGE_POLLING_INTERVAL_MS);
|
|
478
|
-
}
|
|
479
|
-
pauseMessagePolling() {
|
|
480
|
-
if (this.pollingIntervalRef) {
|
|
481
|
-
clearInterval(this.pollingIntervalRef);
|
|
482
|
-
this.pollingIntervalRef = undefined;
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
resumeMessagePolling() {
|
|
486
|
-
// Resume message polling after task polling is complete
|
|
487
|
-
this.startPolling();
|
|
488
|
-
}
|
|
489
|
-
async pollForMessages() {
|
|
490
|
-
if (!this.sessionId)
|
|
491
|
-
return;
|
|
492
|
-
try {
|
|
493
|
-
const url = new URL(`${this.getApiBaseUrl()}/api/chat/${this.sessionId}/poll/`);
|
|
494
|
-
if (this.messages && this.messages.length > 0) {
|
|
495
|
-
url.searchParams.set('since', this.messages.at(-1).created_at);
|
|
496
|
-
}
|
|
497
|
-
const response = await fetch(url.toString());
|
|
498
|
-
if (!response.ok)
|
|
499
|
-
return; // Silently fail for polling
|
|
500
|
-
const data = await response.json();
|
|
501
|
-
if (data.messages.length > 0) {
|
|
502
|
-
this.messages = [...this.messages, ...data.messages];
|
|
503
|
-
this.saveSessionToStorage();
|
|
504
|
-
this.scrollToBottom();
|
|
505
|
-
this.focusInput();
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
catch (_a) {
|
|
509
|
-
// Silently fail for polling
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
scrollToBottom() {
|
|
459
|
+
/**
|
|
460
|
+
* Scroll the message container to the bottom.
|
|
461
|
+
* @param forceEnd When `false`, scroll the top of the last message into view.
|
|
462
|
+
* When `true`, scroll all the way to the end of the last message.
|
|
463
|
+
*/
|
|
464
|
+
scrollToBottom(forceEnd = false) {
|
|
513
465
|
setTimeout(() => {
|
|
514
466
|
if (this.messageListRef) {
|
|
515
|
-
|
|
467
|
+
const lastChild = this.messageListRef.lastElementChild;
|
|
468
|
+
if (!forceEnd && lastChild) {
|
|
469
|
+
// scroll so that the top of the last message is in the centre of the message container
|
|
470
|
+
const parentRect = this.messageListRef.getBoundingClientRect();
|
|
471
|
+
const childRect = lastChild.getBoundingClientRect();
|
|
472
|
+
const currentScrollTop = this.messageListRef.scrollTop;
|
|
473
|
+
const childTopRelativeToParent = childRect.top - parentRect.top;
|
|
474
|
+
const targetScroll = currentScrollTop + childTopRelativeToParent - (parentRect.height / 2);
|
|
475
|
+
this.messageListRef.scrollTo({
|
|
476
|
+
top: targetScroll,
|
|
477
|
+
behavior: 'smooth'
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
else {
|
|
481
|
+
this.messageListRef.scrollTop = this.messageListRef.scrollHeight;
|
|
482
|
+
}
|
|
516
483
|
}
|
|
517
484
|
}, OcsChat.SCROLL_DELAY_MS);
|
|
518
485
|
}
|
|
@@ -533,50 +500,18 @@ export class OcsChat {
|
|
|
533
500
|
this.messageInput = event.target.value;
|
|
534
501
|
}
|
|
535
502
|
handleFileSelect(event) {
|
|
536
|
-
var _a;
|
|
537
503
|
if (!this.allowAttachments)
|
|
538
504
|
return;
|
|
539
505
|
const input = event.target;
|
|
540
506
|
if (!input.files || input.files.length === 0)
|
|
541
507
|
return;
|
|
542
|
-
|
|
543
|
-
let totalSize = this.selectedFiles.reduce((sum, f) => sum + f.file.size, 0);
|
|
544
|
-
for (let i = 0; i < input.files.length; i++) {
|
|
545
|
-
const file = input.files[i];
|
|
546
|
-
const ext = '.' + ((_a = file.name.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase());
|
|
547
|
-
if (!OcsChat.SUPPORTED_FILE_EXTENSIONS.includes(ext)) {
|
|
548
|
-
newFiles.push({
|
|
549
|
-
file,
|
|
550
|
-
error: `File type ${ext} not supported`
|
|
551
|
-
});
|
|
552
|
-
continue;
|
|
553
|
-
}
|
|
554
|
-
const fileSizeMB = file.size / (1024 * 1024);
|
|
555
|
-
if (fileSizeMB > OcsChat.MAX_FILE_SIZE_MB) {
|
|
556
|
-
newFiles.push({
|
|
557
|
-
file,
|
|
558
|
-
error: `File exceeds ${OcsChat.MAX_FILE_SIZE_MB}MB limit`
|
|
559
|
-
});
|
|
560
|
-
continue;
|
|
561
|
-
}
|
|
562
|
-
totalSize += file.size;
|
|
563
|
-
const totalSizeMB = totalSize / (1024 * 1024);
|
|
564
|
-
if (totalSizeMB > OcsChat.MAX_TOTAL_SIZE_MB) {
|
|
565
|
-
newFiles.push({
|
|
566
|
-
file,
|
|
567
|
-
error: `Total size exceeds ${OcsChat.MAX_TOTAL_SIZE_MB}MB limit`
|
|
568
|
-
});
|
|
569
|
-
continue;
|
|
570
|
-
}
|
|
571
|
-
newFiles.push({ file });
|
|
572
|
-
}
|
|
573
|
-
this.selectedFiles = [...this.selectedFiles, ...newFiles];
|
|
508
|
+
this.selectedFiles = this.attachmentManager.addFiles(this.selectedFiles, input.files);
|
|
574
509
|
input.value = '';
|
|
575
510
|
}
|
|
576
511
|
removeSelectedFile(index) {
|
|
577
512
|
if (!this.allowAttachments)
|
|
578
513
|
return;
|
|
579
|
-
this.selectedFiles = this.
|
|
514
|
+
this.selectedFiles = this.attachmentManager.removeFile(this.selectedFiles, index);
|
|
580
515
|
}
|
|
581
516
|
formatFileSize(bytes) {
|
|
582
517
|
if (bytes === 0)
|
|
@@ -603,6 +538,11 @@ export class OcsChat {
|
|
|
603
538
|
* @param visible - The new value for the field.
|
|
604
539
|
*/
|
|
605
540
|
async visibilityHandler(visible) {
|
|
541
|
+
if (this.isButtonDragging) {
|
|
542
|
+
this.isButtonDragging = false;
|
|
543
|
+
this.buttonWasDragged = false;
|
|
544
|
+
this.removeButtonEventListeners();
|
|
545
|
+
}
|
|
606
546
|
if (visible) {
|
|
607
547
|
this.initializePosition();
|
|
608
548
|
}
|
|
@@ -610,10 +550,86 @@ export class OcsChat {
|
|
|
610
550
|
await this.startSession();
|
|
611
551
|
}
|
|
612
552
|
else if (!visible) {
|
|
613
|
-
this.
|
|
553
|
+
this.stopMessagePolling();
|
|
554
|
+
}
|
|
555
|
+
else {
|
|
556
|
+
this.scrollToBottom(true);
|
|
557
|
+
this.startMessagePolling();
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
startTaskPolling(taskId) {
|
|
561
|
+
if (!this.sessionId)
|
|
562
|
+
return;
|
|
563
|
+
this.currentPollTaskId = taskId;
|
|
564
|
+
this.isTyping = true;
|
|
565
|
+
this.stopMessagePolling();
|
|
566
|
+
if (this.taskPollingHandle) {
|
|
567
|
+
this.taskPollingHandle.cancel();
|
|
568
|
+
}
|
|
569
|
+
this.taskPollingHandle = this.getChatService().pollTask(this.sessionId, taskId, {
|
|
570
|
+
onMessage: (message) => {
|
|
571
|
+
this.messages = [...this.messages, message];
|
|
572
|
+
this.saveSessionToStorage();
|
|
573
|
+
this.scrollToBottom();
|
|
574
|
+
this.isTyping = false;
|
|
575
|
+
this.currentPollTaskId = '';
|
|
576
|
+
this.taskPollingHandle = undefined;
|
|
577
|
+
this.startMessagePolling();
|
|
578
|
+
this.focusInput();
|
|
579
|
+
},
|
|
580
|
+
onTimeout: () => {
|
|
581
|
+
const timeoutMessage = {
|
|
582
|
+
created_at: new Date().toISOString(),
|
|
583
|
+
role: 'system',
|
|
584
|
+
content: 'The response is taking longer than expected. The system may be experiencing delays. Please try sending your message again.',
|
|
585
|
+
attachments: []
|
|
586
|
+
};
|
|
587
|
+
this.messages = [...this.messages, timeoutMessage];
|
|
588
|
+
this.saveSessionToStorage();
|
|
589
|
+
this.scrollToBottom();
|
|
590
|
+
this.isTyping = false;
|
|
591
|
+
this.currentPollTaskId = '';
|
|
592
|
+
this.taskPollingHandle = undefined;
|
|
593
|
+
this.startMessagePolling();
|
|
594
|
+
this.focusInput();
|
|
595
|
+
},
|
|
596
|
+
onError: (error) => {
|
|
597
|
+
this.handleError(error.message);
|
|
598
|
+
this.taskPollingHandle = undefined;
|
|
599
|
+
this.startMessagePolling();
|
|
600
|
+
}
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
startMessagePolling() {
|
|
604
|
+
if (!this.sessionId || this.currentPollTaskId || !this.visible) {
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
if (this.messagePollingHandle) {
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
this.messagePollingHandle = this.getChatService().startMessagePolling(this.sessionId, {
|
|
611
|
+
getSince: () => { var _a; return this.messages.length > 0 ? (_a = this.messages.at(-1)) === null || _a === void 0 ? void 0 : _a.created_at : undefined; },
|
|
612
|
+
onMessages: (messages) => {
|
|
613
|
+
if (messages.length === 0)
|
|
614
|
+
return;
|
|
615
|
+
this.messages = [...this.messages, ...messages];
|
|
616
|
+
this.saveSessionToStorage();
|
|
617
|
+
this.scrollToBottom();
|
|
618
|
+
this.focusInput();
|
|
619
|
+
},
|
|
620
|
+
onError: () => {
|
|
621
|
+
// Silently ignore polling errors to match previous behaviour
|
|
622
|
+
}
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
stopMessagePolling() {
|
|
626
|
+
var _a;
|
|
627
|
+
if (this.messagePollingHandle) {
|
|
628
|
+
this.messagePollingHandle.stop();
|
|
629
|
+
this.messagePollingHandle = undefined;
|
|
614
630
|
}
|
|
615
631
|
else {
|
|
616
|
-
this.
|
|
632
|
+
(_a = this.chatService) === null || _a === void 0 ? void 0 : _a.stopMessagePolling();
|
|
617
633
|
}
|
|
618
634
|
}
|
|
619
635
|
setPosition(position) {
|
|
@@ -634,7 +650,6 @@ export class OcsChat {
|
|
|
634
650
|
const actualChatWidth = Math.min(windowWidth, this.chatWindowFullscreenWidth);
|
|
635
651
|
const centeredX = (windowWidth - actualChatWidth) / 2;
|
|
636
652
|
const maxOffset = (windowWidth - actualChatWidth) / 2;
|
|
637
|
-
console.log(windowWidth, actualChatWidth, centeredX, maxOffset);
|
|
638
653
|
return { windowWidth, actualChatWidth, centeredX, maxOffset };
|
|
639
654
|
}
|
|
640
655
|
getPositionStyles() {
|
|
@@ -756,25 +771,181 @@ export class OcsChat {
|
|
|
756
771
|
document.removeEventListener('touchmove', this.handleTouchMove);
|
|
757
772
|
document.removeEventListener('touchend', this.handleTouchEnd);
|
|
758
773
|
}
|
|
759
|
-
|
|
760
|
-
|
|
774
|
+
// Button positioning and drag handlers
|
|
775
|
+
initializeButtonPosition() {
|
|
776
|
+
const computedStyle = getComputedStyle(this.host);
|
|
777
|
+
const position = computedStyle.getPropertyValue('position');
|
|
778
|
+
// Only enable dragging if the host element is positioned fixed
|
|
779
|
+
if (position !== 'fixed') {
|
|
780
|
+
return;
|
|
781
|
+
}
|
|
782
|
+
const rect = this.host.getBoundingClientRect();
|
|
783
|
+
const windowWidth = window.innerWidth;
|
|
784
|
+
const windowHeight = window.innerHeight;
|
|
785
|
+
const left = computedStyle.getPropertyValue('left');
|
|
786
|
+
const right = computedStyle.getPropertyValue('right');
|
|
787
|
+
const top = computedStyle.getPropertyValue('top');
|
|
788
|
+
const bottom = computedStyle.getPropertyValue('bottom');
|
|
789
|
+
const hasLeft = !this.isAutoPosition(left);
|
|
790
|
+
const hasTop = !this.isAutoPosition(top);
|
|
791
|
+
this.buttonHorizontalSide = hasLeft ? 'left' : 'right';
|
|
792
|
+
this.buttonVerticalSide = hasTop ? 'top' : 'bottom';
|
|
793
|
+
const resolvedRight = this.getNumericPositionValue(right, Math.max(0, windowWidth - rect.right));
|
|
794
|
+
const resolvedLeft = this.getNumericPositionValue(left, Math.max(0, rect.left));
|
|
795
|
+
const resolvedBottom = this.getNumericPositionValue(bottom, Math.max(0, windowHeight - rect.bottom));
|
|
796
|
+
const resolvedTop = this.getNumericPositionValue(top, Math.max(0, rect.top));
|
|
797
|
+
const horizontalValue = this.buttonHorizontalSide === 'left' ? resolvedLeft : resolvedRight;
|
|
798
|
+
const verticalValue = this.buttonVerticalSide === 'top' ? resolvedTop : resolvedBottom;
|
|
799
|
+
this.buttonPosition = {
|
|
800
|
+
x: horizontalValue,
|
|
801
|
+
y: verticalValue
|
|
802
|
+
};
|
|
803
|
+
// Apply the position to the host
|
|
804
|
+
this.updateHostPosition();
|
|
805
|
+
}
|
|
806
|
+
updateHostPosition() {
|
|
807
|
+
this.host.style.position = 'fixed';
|
|
808
|
+
if (this.buttonHorizontalSide === 'left') {
|
|
809
|
+
this.host.style.left = `${this.buttonPosition.x}px`;
|
|
810
|
+
this.host.style.right = 'auto';
|
|
811
|
+
}
|
|
812
|
+
else {
|
|
813
|
+
this.host.style.right = `${this.buttonPosition.x}px`;
|
|
814
|
+
this.host.style.left = 'auto';
|
|
815
|
+
}
|
|
816
|
+
if (this.buttonVerticalSide === 'top') {
|
|
817
|
+
this.host.style.top = `${this.buttonPosition.y}px`;
|
|
818
|
+
this.host.style.bottom = 'auto';
|
|
819
|
+
}
|
|
820
|
+
else {
|
|
821
|
+
this.host.style.bottom = `${this.buttonPosition.y}px`;
|
|
822
|
+
this.host.style.top = 'auto';
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
isButtonDraggable() {
|
|
826
|
+
const computedStyle = getComputedStyle(this.host);
|
|
827
|
+
return computedStyle.getPropertyValue('position') === 'fixed';
|
|
828
|
+
}
|
|
829
|
+
updateButtonPosition(pointer) {
|
|
830
|
+
var _a, _b;
|
|
831
|
+
const windowWidth = window.innerWidth;
|
|
832
|
+
const windowHeight = window.innerHeight;
|
|
833
|
+
const buttonWidth = ((_a = this.buttonRef) === null || _a === void 0 ? void 0 : _a.offsetWidth) || 60;
|
|
834
|
+
const buttonHeight = ((_b = this.buttonRef) === null || _b === void 0 ? void 0 : _b.offsetHeight) || 60;
|
|
835
|
+
const minPadding = 10;
|
|
836
|
+
const candidateLeft = pointer.clientX - this.buttonDragOffset.x;
|
|
837
|
+
const candidateTop = pointer.clientY - this.buttonDragOffset.y;
|
|
838
|
+
const minLeft = minPadding;
|
|
839
|
+
const maxLeft = windowWidth - buttonWidth - minPadding;
|
|
840
|
+
const minTop = minPadding;
|
|
841
|
+
const maxTop = windowHeight - buttonHeight - minPadding;
|
|
842
|
+
const constrainedLeft = Math.max(minLeft, Math.min(candidateLeft, maxLeft));
|
|
843
|
+
const constrainedTop = Math.max(minTop, Math.min(candidateTop, maxTop));
|
|
844
|
+
const newHorizontalValue = this.buttonHorizontalSide === 'left'
|
|
845
|
+
? constrainedLeft
|
|
846
|
+
: Math.max(minPadding, windowWidth - (constrainedLeft + buttonWidth));
|
|
847
|
+
const newVerticalValue = this.buttonVerticalSide === 'top'
|
|
848
|
+
? constrainedTop
|
|
849
|
+
: Math.max(minPadding, windowHeight - (constrainedTop + buttonHeight));
|
|
850
|
+
if (newHorizontalValue !== this.buttonPosition.x || newVerticalValue !== this.buttonPosition.y) {
|
|
851
|
+
this.buttonWasDragged = true;
|
|
852
|
+
this.buttonPosition = { x: newHorizontalValue, y: newVerticalValue };
|
|
853
|
+
if (this.rafId === null) {
|
|
854
|
+
this.rafId = requestAnimationFrame(() => {
|
|
855
|
+
this.updateHostPosition();
|
|
856
|
+
this.rafId = null;
|
|
857
|
+
});
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
addButtonEventListeners() {
|
|
862
|
+
if (this.buttonListenersAttached) {
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
document.addEventListener('mousemove', this.handleButtonMouseMove);
|
|
866
|
+
document.addEventListener('mouseup', this.handleButtonMouseUp);
|
|
867
|
+
document.addEventListener('touchmove', this.handleButtonTouchMove, { passive: false });
|
|
868
|
+
document.addEventListener('touchend', this.handleButtonTouchEnd);
|
|
869
|
+
this.buttonListenersAttached = true;
|
|
870
|
+
}
|
|
871
|
+
removeButtonEventListeners() {
|
|
872
|
+
if (!this.buttonListenersAttached) {
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
875
|
+
if (this.rafId !== null) {
|
|
876
|
+
cancelAnimationFrame(this.rafId);
|
|
877
|
+
this.rafId = null;
|
|
878
|
+
}
|
|
879
|
+
document.removeEventListener('mousemove', this.handleButtonMouseMove);
|
|
880
|
+
document.removeEventListener('mouseup', this.handleButtonMouseUp);
|
|
881
|
+
document.removeEventListener('touchmove', this.handleButtonTouchMove);
|
|
882
|
+
document.removeEventListener('touchend', this.handleButtonTouchEnd);
|
|
883
|
+
this.buttonListenersAttached = false;
|
|
884
|
+
}
|
|
885
|
+
isAutoPosition(value) {
|
|
886
|
+
const trimmed = value.trim();
|
|
887
|
+
return trimmed === '' || trimmed === 'auto';
|
|
888
|
+
}
|
|
889
|
+
parsePixelValue(value) {
|
|
890
|
+
const trimmed = value.trim();
|
|
891
|
+
if (trimmed === '' || trimmed === 'auto') {
|
|
892
|
+
return null;
|
|
893
|
+
}
|
|
894
|
+
if (trimmed.endsWith('px')) {
|
|
895
|
+
const parsed = parseFloat(trimmed);
|
|
896
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
897
|
+
}
|
|
898
|
+
const numeric = Number(trimmed);
|
|
899
|
+
if (Number.isFinite(numeric)) {
|
|
900
|
+
return numeric;
|
|
901
|
+
}
|
|
902
|
+
return null;
|
|
903
|
+
}
|
|
904
|
+
getNumericPositionValue(value, fallback) {
|
|
905
|
+
const parsed = this.parsePixelValue(value);
|
|
906
|
+
if (parsed !== null) {
|
|
907
|
+
return parsed;
|
|
908
|
+
}
|
|
909
|
+
return fallback;
|
|
910
|
+
}
|
|
911
|
+
getWelcomeMessages() {
|
|
912
|
+
const translated = this.translationManager.getArray("content.welcomeMessages");
|
|
913
|
+
return translated && translated.length > 0
|
|
914
|
+
? translated
|
|
915
|
+
: this.parsedWelcomeMessages;
|
|
916
|
+
}
|
|
917
|
+
getStarterQuestions() {
|
|
918
|
+
const translated = this.translationManager.getArray("content.starterQuestions");
|
|
919
|
+
return translated && translated.length > 0
|
|
920
|
+
? translated
|
|
921
|
+
: this.parsedStarterQuestions;
|
|
761
922
|
}
|
|
762
923
|
getButtonClasses() {
|
|
763
|
-
const
|
|
924
|
+
const buttonText = this.translationManager.get('branding.buttonText', this.buttonText);
|
|
925
|
+
const hasText = !!(buttonText && buttonText.trim());
|
|
764
926
|
const baseClass = hasText ? 'chat-btn-text' : 'chat-btn-icon';
|
|
765
927
|
const shapeClass = this.buttonShape === 'round' ? 'round' : '';
|
|
766
928
|
return `${baseClass} ${shapeClass}`.trim();
|
|
767
929
|
}
|
|
768
930
|
renderButton() {
|
|
769
|
-
|
|
931
|
+
var _a;
|
|
932
|
+
const buttonText = this.translationManager.get('branding.buttonText', this.buttonText);
|
|
933
|
+
const hasText = !!(buttonText && buttonText.trim());
|
|
770
934
|
const hasCustomIcon = this.iconUrl && this.iconUrl.trim();
|
|
771
|
-
const iconSrc = hasCustomIcon ? this.iconUrl : this.getDefaultIconUrl();
|
|
772
935
|
const buttonClasses = this.getButtonClasses();
|
|
936
|
+
const finalButtonText = buttonText !== null && buttonText !== void 0 ? buttonText : '';
|
|
937
|
+
const openLabel = (_a = this.translationManager.get('launcher.open')) !== null && _a !== void 0 ? _a : '';
|
|
938
|
+
const buttonAriaLabel = finalButtonText ? `${openLabel} - ${finalButtonText}` : openLabel;
|
|
939
|
+
// Only show drag cursor if button is draggable
|
|
940
|
+
const isDraggable = this.isButtonDraggable();
|
|
941
|
+
const buttonStyle = isDraggable ? {
|
|
942
|
+
cursor: this.isButtonDragging ? 'grabbing' : 'grab',
|
|
943
|
+
} : {};
|
|
773
944
|
if (hasText) {
|
|
774
|
-
return (h("button", { class: buttonClasses, onClick: () => this.
|
|
945
|
+
return (h("button", { ref: (el) => this.buttonRef = el, class: buttonClasses, "aria-label": buttonAriaLabel, title: finalButtonText || openLabel, style: buttonStyle, onClick: () => this.handleButtonClick(), onMouseDown: (e) => this.handleButtonMouseDown(e), onTouchStart: (e) => this.handleButtonTouchStart(e), "aria-grabbed": this.isButtonDragging, "aria-describedby": isDraggable ? "chat-button-drag-hint" : undefined }, hasCustomIcon ? h("img", { src: this.iconUrl, alt: "" }) : h(OcsWidgetAvatar, null), h("span", null, finalButtonText), isDraggable && (h("span", { id: "chat-button-drag-hint", style: { display: 'none' } }, "Draggable. Use mouse or touch to reposition."))));
|
|
775
946
|
}
|
|
776
947
|
else {
|
|
777
|
-
return (h("button", { class: buttonClasses, onClick: () => this.
|
|
948
|
+
return (h("button", { ref: (el) => this.buttonRef = el, class: buttonClasses, "aria-label": openLabel, title: openLabel, style: buttonStyle, onClick: () => this.handleButtonClick(), onMouseDown: (e) => this.handleButtonMouseDown(e), onTouchStart: (e) => this.handleButtonTouchStart(e), "aria-grabbed": this.isButtonDragging, "aria-describedby": isDraggable ? "chat-button-drag-hint" : undefined }, hasCustomIcon ? h("img", { src: this.iconUrl, alt: "" }) : h(OcsWidgetAvatar, null), isDraggable && (h("span", { id: "chat-button-drag-hint", style: { display: 'none' } }, "Draggable. Use mouse or touch to reposition."))));
|
|
778
949
|
}
|
|
779
950
|
}
|
|
780
951
|
getStorageKeys() {
|
|
@@ -910,18 +1081,18 @@ export class OcsChat {
|
|
|
910
1081
|
if (this.error && !this.sessionId) {
|
|
911
1082
|
return (h(Host, null, h("p", { class: "error-message" }, this.error)));
|
|
912
1083
|
}
|
|
913
|
-
return (h(Host, null, this.renderButton(), this.visible && (h("div", { ref: (el) => this.chatWindowRef = el, id: "ocs-chat-window", class: this.getPositionClasses(), style: this.getPositionStyles() }, h("div", { class: `chat-header ${this.isDragging ? 'chat-header-dragging' : 'chat-header-draggable'}`, onMouseDown: this.handleMouseDown, onTouchStart: this.handleTouchStart }, h("div", { class: "drag-indicator" }, h("div", { class: "drag-dots header-button" }, h(GripDotsVerticalIcon, null))), h("div", { class: "header-text" }, this.headerText), h("div", { class: "header-buttons" }, this.messages.length > 0 && (h("button", { class: "header-button", onClick: () => this.showConfirmationDialog(), title:
|
|
1084
|
+
return (h(Host, null, this.renderButton(), this.visible && (h("div", { ref: (el) => this.chatWindowRef = el, id: "ocs-chat-window", class: this.getPositionClasses(), style: this.getPositionStyles() }, h("div", { class: `chat-header ${this.isDragging ? 'chat-header-dragging' : 'chat-header-draggable'}`, onMouseDown: this.handleMouseDown, onTouchStart: this.handleTouchStart }, h("div", { class: "drag-indicator" }, h("div", { class: "drag-dots header-button" }, h(GripDotsVerticalIcon, null))), h("div", { class: "header-text" }, this.translationManager.get('branding.headerText', this.headerText)), h("div", { class: "header-buttons" }, this.messages.length > 0 && (h("button", { class: "header-button", onClick: () => this.showConfirmationDialog(), title: this.translationManager.get('window.newChat'), "aria-label": this.translationManager.get('window.newChat') }, h(PlusWithCircleIcon, null))), this.allowFullScreen && h("button", { class: "header-button fullscreen-button", onClick: () => this.toggleFullscreen(), title: this.isFullscreen ? this.translationManager.get('window.exitFullscreen') : this.translationManager.get('window.fullscreen'), "aria-label": this.isFullscreen ? this.translationManager.get('window.exitFullscreen') : this.translationManager.get('window.fullscreen') }, this.isFullscreen ? h(ArrowsPointingInIcon, null) : h(ArrowsPointingOutIcon, null)), h("button", { class: "header-button", onClick: () => this.visible = false, "aria-label": this.translationManager.get('window.close') }, h(XMarkIcon, null)))), this.showNewChatConfirmation && (h("div", { class: "confirmation-overlay" }, h("div", { class: "confirmation-dialog" }, h("div", { class: "confirmation-content" }, h("h3", { class: "confirmation-title" }, this.translationManager.get('modal.newChatTitle')), h("p", { class: "confirmation-message" }, this.translationManager.get('modal.newChatBody', this.newChatConfirmationMessage)), h("div", { class: "confirmation-buttons" }, h("button", { class: "confirmation-button confirmation-button-cancel", onClick: () => this.hideConfirmationDialog() }, this.translationManager.get('modal.cancel')), h("button", { class: "confirmation-button confirmation-button-confirm", onClick: () => this.confirmNewChat() }, this.translationManager.get('modal.confirm'))))))), h("div", { class: "chat-content" }, this.isLoading && !this.sessionId && (h("div", { class: "loading-container" }, h("div", { class: "loading-spinner" }), h("span", { class: "loading-text" }, this.translationManager.get('status.starting')))), (h("div", { ref: (el) => this.messageListRef = el, class: "messages-container" }, this.messages.length === 0 && this.parsedWelcomeMessages.length > 0 && (h("div", { class: "welcome-messages" }, this.getWelcomeMessages().map((message, index) => (h("div", { key: `welcome-${index}`, class: "message-row message-row-assistant" }, h("div", { class: "message-bubble message-bubble-assistant" }, h("div", { class: "chat-markdown", innerHTML: renderMarkdownComplete(message) }))))))), this.messages.map((message, index) => (h("div", { key: index, class: `message-row ${message.role === 'user' ? 'message-row-user' : 'message-row-assistant'}` }, h("div", { class: `message-bubble ${message.role === 'user'
|
|
914
1085
|
? 'message-bubble-user'
|
|
915
1086
|
: message.role === 'assistant'
|
|
916
1087
|
? 'message-bubble-assistant'
|
|
917
|
-
: 'message-bubble-system'}` }, h("div", { class: "chat-markdown", innerHTML: renderMarkdownComplete(message.content) }), message.attachments && message.attachments.length > 0 && (h("div", { class: "message-attachments" }, message.attachments.map((attachment, attachmentIndex) => (h("div", { key: attachmentIndex, class: "flex items-center gap-[0.5em]" }, h("span", { class: "message-attachment-icon" }, h(PaperClipIcon, null)), h("span", { class: "message-attachment-name" }, attachment.name)))))), h("div", { class: "message-timestamp" }, this.formatTime(message.created_at)))))), this.isTyping && (h("div", null, h("div", { class: "typing-indicator" }, h("div", { class: "typing-progress" })), h("div", { class: "typing-text" }, h("span", null, this.typingIndicatorText), h("span", { class: "typing-dots" })))))), this.messages.length === 0 && this.parsedStarterQuestions.length > 0 && (h("div", { class: "starter-questions" }, this.
|
|
1088
|
+
: 'message-bubble-system'}` }, h("div", { class: "chat-markdown", innerHTML: renderMarkdownComplete(message.content) }), message.attachments && message.attachments.length > 0 && (h("div", { class: "message-attachments" }, message.attachments.map((attachment, attachmentIndex) => (h("div", { key: attachmentIndex, class: "flex items-center gap-[0.5em]" }, h("span", { class: "message-attachment-icon" }, h(PaperClipIcon, null)), h("span", { class: "message-attachment-name" }, attachment.name)))))), h("div", { class: "message-timestamp" }, this.formatTime(message.created_at)))))), this.isTyping && (h("div", null, h("div", { class: "typing-indicator" }, h("div", { class: "typing-progress" })), h("div", { class: "typing-text" }, h("span", null, this.translationManager.get('status.typing', this.typingIndicatorText)), h("span", { class: "typing-dots loading" })))))), this.messages.length === 0 && this.parsedStarterQuestions.length > 0 && (h("div", { class: "starter-questions" }, this.getStarterQuestions().map((question, index) => (h("div", { key: `starter-${index}`, class: "starter-question-row" }, h("button", { class: "starter-question", onClick: () => this.handleStarterQuestionClick(question) }, question)))))), this.allowAttachments && this.selectedFiles.length > 0 && (h("div", { class: "selected-files-container" }, h("div", { class: "space-y-[0.25em]" }, this.selectedFiles.map((selectedFile, index) => (h("div", { key: index, class: "selected-file-item" }, h("div", { class: "flex items-center gap-[0.5em]" }, h("span", { class: "selected-file-icon" }, h(PaperClipIcon, null)), h("span", null, selectedFile.file.name), h("span", { class: "selected-file-size" }, "(", this.formatFileSize(selectedFile.file.size), ")"), selectedFile.error && (h("span", { class: "selected-file-error" }, selectedFile.error)), selectedFile.uploaded && (h("span", { class: "selected-file-success-icon" }, h(CheckDocumentIcon, null)))), h("button", { onClick: () => this.removeSelectedFile(index), class: "selected-file-remove-button", "aria-label": this.translationManager.get('attach.remove') }, h(XIcon, null)))))))), this.sessionId && (h("div", { class: "input-area" }, h("div", { class: "input-container" }, h("textarea", { ref: (el) => this.textareaRef = el, class: "message-textarea", rows: 1, placeholder: this.translationManager.get('composer.placeholder'), value: this.messageInput, onInput: (e) => this.handleInputChange(e), onKeyPress: (e) => this.handleKeyPress(e), disabled: this.isTyping || this.isUploadingFiles }), this.allowAttachments && (h("input", { ref: (el) => {
|
|
918
1089
|
// Unclear why but after removing all attachments this is being set to `null`.
|
|
919
1090
|
if (el) {
|
|
920
1091
|
this.fileInputRef = el;
|
|
921
1092
|
}
|
|
922
|
-
}, id: "ocs-file-input", type: "file", multiple: true, accept: OcsChat.SUPPORTED_FILE_EXTENSIONS.join(','), onChange: (e) => this.handleFileSelect(e), class: "hidden" })), this.allowAttachments && (h("button", { class: "file-attachment-button", onClick: () => { var _a; return (_a = this.fileInputRef) === null || _a === void 0 ? void 0 : _a.click(); }, disabled: this.isTyping || this.isUploadingFiles, title:
|
|
1093
|
+
}, id: "ocs-file-input", type: "file", multiple: true, accept: OcsChat.SUPPORTED_FILE_EXTENSIONS.join(','), onChange: (e) => this.handleFileSelect(e), class: "hidden" })), this.allowAttachments && (h("button", { class: "file-attachment-button", onClick: () => { var _a; return (_a = this.fileInputRef) === null || _a === void 0 ? void 0 : _a.click(); }, disabled: this.isTyping || this.isUploadingFiles, title: this.translationManager.get('attach.add'), "aria-label": this.translationManager.get('attach.add') }, h(PaperClipIcon, null))), h("button", { class: `send-button ${!this.isTyping && !!this.messageInput.trim()
|
|
923
1094
|
? 'send-button-enabled'
|
|
924
|
-
: 'send-button-disabled'}`, onClick: () => this.sendMessage(this.messageInput), disabled: this.isTyping || this.isUploadingFiles || !this.messageInput.trim() }, this.isUploadingFiles ? '
|
|
1095
|
+
: 'send-button-disabled'}`, onClick: () => this.sendMessage(this.messageInput), disabled: this.isTyping || this.isUploadingFiles || !this.messageInput.trim() }, this.isUploadingFiles ? `${this.translationManager.get('status.uploading')}...` : this.translationManager.get('composer.send'))))), h("div", { class: "flex items-center justify-center text-[0.8em] font-light w-full text-slate-500 py-[2px]" }, h("p", null, this.translationManager.get('branding.poweredBy'), ' ', " ", h("a", { class: "underline", href: "https://www.dimagi.com", target: "_blank" }, "Dimagi"))))))));
|
|
925
1096
|
}
|
|
926
1097
|
static get is() { return "open-chat-studio-widget"; }
|
|
927
1098
|
static get encapsulation() { return "shadow"; }
|
|
@@ -939,6 +1110,7 @@ export class OcsChat {
|
|
|
939
1110
|
return {
|
|
940
1111
|
"chatbotId": {
|
|
941
1112
|
"type": "string",
|
|
1113
|
+
"attribute": "chatbot-id",
|
|
942
1114
|
"mutable": false,
|
|
943
1115
|
"complexType": {
|
|
944
1116
|
"original": "string",
|
|
@@ -953,11 +1125,11 @@ export class OcsChat {
|
|
|
953
1125
|
},
|
|
954
1126
|
"getter": false,
|
|
955
1127
|
"setter": false,
|
|
956
|
-
"attribute": "chatbot-id",
|
|
957
1128
|
"reflect": false
|
|
958
1129
|
},
|
|
959
1130
|
"apiBaseUrl": {
|
|
960
1131
|
"type": "string",
|
|
1132
|
+
"attribute": "api-base-url",
|
|
961
1133
|
"mutable": false,
|
|
962
1134
|
"complexType": {
|
|
963
1135
|
"original": "string",
|
|
@@ -968,16 +1140,16 @@ export class OcsChat {
|
|
|
968
1140
|
"optional": true,
|
|
969
1141
|
"docs": {
|
|
970
1142
|
"tags": [],
|
|
971
|
-
"text": "The base URL for the API
|
|
1143
|
+
"text": "The base URL for the API."
|
|
972
1144
|
},
|
|
973
1145
|
"getter": false,
|
|
974
1146
|
"setter": false,
|
|
975
|
-
"attribute": "api-base-url",
|
|
976
1147
|
"reflect": false,
|
|
977
|
-
"defaultValue": "\"https://
|
|
1148
|
+
"defaultValue": "\"https://www.openchatstudio.com\""
|
|
978
1149
|
},
|
|
979
1150
|
"buttonText": {
|
|
980
1151
|
"type": "string",
|
|
1152
|
+
"attribute": "button-text",
|
|
981
1153
|
"mutable": false,
|
|
982
1154
|
"complexType": {
|
|
983
1155
|
"original": "string",
|
|
@@ -992,11 +1164,11 @@ export class OcsChat {
|
|
|
992
1164
|
},
|
|
993
1165
|
"getter": false,
|
|
994
1166
|
"setter": false,
|
|
995
|
-
"attribute": "button-text",
|
|
996
1167
|
"reflect": false
|
|
997
1168
|
},
|
|
998
1169
|
"iconUrl": {
|
|
999
1170
|
"type": "string",
|
|
1171
|
+
"attribute": "icon-url",
|
|
1000
1172
|
"mutable": false,
|
|
1001
1173
|
"complexType": {
|
|
1002
1174
|
"original": "string",
|
|
@@ -1011,11 +1183,30 @@ export class OcsChat {
|
|
|
1011
1183
|
},
|
|
1012
1184
|
"getter": false,
|
|
1013
1185
|
"setter": false,
|
|
1014
|
-
"
|
|
1186
|
+
"reflect": false
|
|
1187
|
+
},
|
|
1188
|
+
"embedKey": {
|
|
1189
|
+
"type": "string",
|
|
1190
|
+
"attribute": "embed-key",
|
|
1191
|
+
"mutable": false,
|
|
1192
|
+
"complexType": {
|
|
1193
|
+
"original": "string",
|
|
1194
|
+
"resolved": "string",
|
|
1195
|
+
"references": {}
|
|
1196
|
+
},
|
|
1197
|
+
"required": false,
|
|
1198
|
+
"optional": true,
|
|
1199
|
+
"docs": {
|
|
1200
|
+
"tags": [],
|
|
1201
|
+
"text": "Authentication key for embedded channels"
|
|
1202
|
+
},
|
|
1203
|
+
"getter": false,
|
|
1204
|
+
"setter": false,
|
|
1015
1205
|
"reflect": false
|
|
1016
1206
|
},
|
|
1017
1207
|
"buttonShape": {
|
|
1018
1208
|
"type": "string",
|
|
1209
|
+
"attribute": "button-shape",
|
|
1019
1210
|
"mutable": false,
|
|
1020
1211
|
"complexType": {
|
|
1021
1212
|
"original": "'round' | 'square'",
|
|
@@ -1030,12 +1221,12 @@ export class OcsChat {
|
|
|
1030
1221
|
},
|
|
1031
1222
|
"getter": false,
|
|
1032
1223
|
"setter": false,
|
|
1033
|
-
"attribute": "button-shape",
|
|
1034
1224
|
"reflect": false,
|
|
1035
1225
|
"defaultValue": "'square'"
|
|
1036
1226
|
},
|
|
1037
1227
|
"headerText": {
|
|
1038
1228
|
"type": "string",
|
|
1229
|
+
"attribute": "header-text",
|
|
1039
1230
|
"mutable": false,
|
|
1040
1231
|
"complexType": {
|
|
1041
1232
|
"original": "''",
|
|
@@ -1050,11 +1241,11 @@ export class OcsChat {
|
|
|
1050
1241
|
},
|
|
1051
1242
|
"getter": false,
|
|
1052
1243
|
"setter": false,
|
|
1053
|
-
"attribute": "header-text",
|
|
1054
1244
|
"reflect": false
|
|
1055
1245
|
},
|
|
1056
1246
|
"newChatConfirmationMessage": {
|
|
1057
1247
|
"type": "string",
|
|
1248
|
+
"attribute": "new-chat-confirmation-message",
|
|
1058
1249
|
"mutable": false,
|
|
1059
1250
|
"complexType": {
|
|
1060
1251
|
"original": "string",
|
|
@@ -1069,12 +1260,11 @@ export class OcsChat {
|
|
|
1069
1260
|
},
|
|
1070
1261
|
"getter": false,
|
|
1071
1262
|
"setter": false,
|
|
1072
|
-
"
|
|
1073
|
-
"reflect": false,
|
|
1074
|
-
"defaultValue": "\"Starting a new chat will clear your current conversation. Continue?\""
|
|
1263
|
+
"reflect": false
|
|
1075
1264
|
},
|
|
1076
1265
|
"visible": {
|
|
1077
1266
|
"type": "boolean",
|
|
1267
|
+
"attribute": "visible",
|
|
1078
1268
|
"mutable": true,
|
|
1079
1269
|
"complexType": {
|
|
1080
1270
|
"original": "boolean",
|
|
@@ -1089,12 +1279,12 @@ export class OcsChat {
|
|
|
1089
1279
|
},
|
|
1090
1280
|
"getter": false,
|
|
1091
1281
|
"setter": false,
|
|
1092
|
-
"attribute": "visible",
|
|
1093
1282
|
"reflect": false,
|
|
1094
1283
|
"defaultValue": "false"
|
|
1095
1284
|
},
|
|
1096
1285
|
"position": {
|
|
1097
1286
|
"type": "string",
|
|
1287
|
+
"attribute": "position",
|
|
1098
1288
|
"mutable": true,
|
|
1099
1289
|
"complexType": {
|
|
1100
1290
|
"original": "'left' | 'center' | 'right'",
|
|
@@ -1109,12 +1299,12 @@ export class OcsChat {
|
|
|
1109
1299
|
},
|
|
1110
1300
|
"getter": false,
|
|
1111
1301
|
"setter": false,
|
|
1112
|
-
"attribute": "position",
|
|
1113
1302
|
"reflect": false,
|
|
1114
1303
|
"defaultValue": "'right'"
|
|
1115
1304
|
},
|
|
1116
1305
|
"welcomeMessages": {
|
|
1117
1306
|
"type": "string",
|
|
1307
|
+
"attribute": "welcome-messages",
|
|
1118
1308
|
"mutable": false,
|
|
1119
1309
|
"complexType": {
|
|
1120
1310
|
"original": "string",
|
|
@@ -1129,11 +1319,11 @@ export class OcsChat {
|
|
|
1129
1319
|
},
|
|
1130
1320
|
"getter": false,
|
|
1131
1321
|
"setter": false,
|
|
1132
|
-
"attribute": "welcome-messages",
|
|
1133
1322
|
"reflect": false
|
|
1134
1323
|
},
|
|
1135
1324
|
"starterQuestions": {
|
|
1136
1325
|
"type": "string",
|
|
1326
|
+
"attribute": "starter-questions",
|
|
1137
1327
|
"mutable": false,
|
|
1138
1328
|
"complexType": {
|
|
1139
1329
|
"original": "string",
|
|
@@ -1148,11 +1338,11 @@ export class OcsChat {
|
|
|
1148
1338
|
},
|
|
1149
1339
|
"getter": false,
|
|
1150
1340
|
"setter": false,
|
|
1151
|
-
"attribute": "starter-questions",
|
|
1152
1341
|
"reflect": false
|
|
1153
1342
|
},
|
|
1154
1343
|
"userId": {
|
|
1155
1344
|
"type": "string",
|
|
1345
|
+
"attribute": "user-id",
|
|
1156
1346
|
"mutable": false,
|
|
1157
1347
|
"complexType": {
|
|
1158
1348
|
"original": "string",
|
|
@@ -1167,11 +1357,11 @@ export class OcsChat {
|
|
|
1167
1357
|
},
|
|
1168
1358
|
"getter": false,
|
|
1169
1359
|
"setter": false,
|
|
1170
|
-
"attribute": "user-id",
|
|
1171
1360
|
"reflect": false
|
|
1172
1361
|
},
|
|
1173
1362
|
"userName": {
|
|
1174
1363
|
"type": "string",
|
|
1364
|
+
"attribute": "user-name",
|
|
1175
1365
|
"mutable": false,
|
|
1176
1366
|
"complexType": {
|
|
1177
1367
|
"original": "string",
|
|
@@ -1186,11 +1376,11 @@ export class OcsChat {
|
|
|
1186
1376
|
},
|
|
1187
1377
|
"getter": false,
|
|
1188
1378
|
"setter": false,
|
|
1189
|
-
"attribute": "user-name",
|
|
1190
1379
|
"reflect": false
|
|
1191
1380
|
},
|
|
1192
1381
|
"persistentSession": {
|
|
1193
1382
|
"type": "boolean",
|
|
1383
|
+
"attribute": "persistent-session",
|
|
1194
1384
|
"mutable": false,
|
|
1195
1385
|
"complexType": {
|
|
1196
1386
|
"original": "boolean",
|
|
@@ -1205,12 +1395,12 @@ export class OcsChat {
|
|
|
1205
1395
|
},
|
|
1206
1396
|
"getter": false,
|
|
1207
1397
|
"setter": false,
|
|
1208
|
-
"attribute": "persistent-session",
|
|
1209
1398
|
"reflect": false,
|
|
1210
1399
|
"defaultValue": "true"
|
|
1211
1400
|
},
|
|
1212
1401
|
"persistentSessionExpire": {
|
|
1213
1402
|
"type": "number",
|
|
1403
|
+
"attribute": "persistent-session-expire",
|
|
1214
1404
|
"mutable": false,
|
|
1215
1405
|
"complexType": {
|
|
1216
1406
|
"original": "number",
|
|
@@ -1225,12 +1415,12 @@ export class OcsChat {
|
|
|
1225
1415
|
},
|
|
1226
1416
|
"getter": false,
|
|
1227
1417
|
"setter": false,
|
|
1228
|
-
"attribute": "persistent-session-expire",
|
|
1229
1418
|
"reflect": false,
|
|
1230
1419
|
"defaultValue": "60 * 24"
|
|
1231
1420
|
},
|
|
1232
1421
|
"allowFullScreen": {
|
|
1233
1422
|
"type": "boolean",
|
|
1423
|
+
"attribute": "allow-full-screen",
|
|
1234
1424
|
"mutable": false,
|
|
1235
1425
|
"complexType": {
|
|
1236
1426
|
"original": "boolean",
|
|
@@ -1245,12 +1435,12 @@ export class OcsChat {
|
|
|
1245
1435
|
},
|
|
1246
1436
|
"getter": false,
|
|
1247
1437
|
"setter": false,
|
|
1248
|
-
"attribute": "allow-full-screen",
|
|
1249
1438
|
"reflect": false,
|
|
1250
1439
|
"defaultValue": "true"
|
|
1251
1440
|
},
|
|
1252
1441
|
"allowAttachments": {
|
|
1253
1442
|
"type": "boolean",
|
|
1443
|
+
"attribute": "allow-attachments",
|
|
1254
1444
|
"mutable": false,
|
|
1255
1445
|
"complexType": {
|
|
1256
1446
|
"original": "boolean",
|
|
@@ -1265,12 +1455,12 @@ export class OcsChat {
|
|
|
1265
1455
|
},
|
|
1266
1456
|
"getter": false,
|
|
1267
1457
|
"setter": false,
|
|
1268
|
-
"attribute": "allow-attachments",
|
|
1269
1458
|
"reflect": false,
|
|
1270
1459
|
"defaultValue": "false"
|
|
1271
1460
|
},
|
|
1272
1461
|
"typingIndicatorText": {
|
|
1273
1462
|
"type": "string",
|
|
1463
|
+
"attribute": "typing-indicator-text",
|
|
1274
1464
|
"mutable": false,
|
|
1275
1465
|
"complexType": {
|
|
1276
1466
|
"original": "string",
|
|
@@ -1285,9 +1475,45 @@ export class OcsChat {
|
|
|
1285
1475
|
},
|
|
1286
1476
|
"getter": false,
|
|
1287
1477
|
"setter": false,
|
|
1288
|
-
"
|
|
1289
|
-
|
|
1290
|
-
|
|
1478
|
+
"reflect": false
|
|
1479
|
+
},
|
|
1480
|
+
"language": {
|
|
1481
|
+
"type": "string",
|
|
1482
|
+
"attribute": "language",
|
|
1483
|
+
"mutable": false,
|
|
1484
|
+
"complexType": {
|
|
1485
|
+
"original": "string",
|
|
1486
|
+
"resolved": "string",
|
|
1487
|
+
"references": {}
|
|
1488
|
+
},
|
|
1489
|
+
"required": false,
|
|
1490
|
+
"optional": true,
|
|
1491
|
+
"docs": {
|
|
1492
|
+
"tags": [],
|
|
1493
|
+
"text": "The language code for the widget UI (e.g., 'en', 'es', 'fr'). Defaults to en"
|
|
1494
|
+
},
|
|
1495
|
+
"getter": false,
|
|
1496
|
+
"setter": false,
|
|
1497
|
+
"reflect": false
|
|
1498
|
+
},
|
|
1499
|
+
"translationsUrl": {
|
|
1500
|
+
"type": "string",
|
|
1501
|
+
"attribute": "translations-url",
|
|
1502
|
+
"mutable": false,
|
|
1503
|
+
"complexType": {
|
|
1504
|
+
"original": "string",
|
|
1505
|
+
"resolved": "string",
|
|
1506
|
+
"references": {}
|
|
1507
|
+
},
|
|
1508
|
+
"required": false,
|
|
1509
|
+
"optional": true,
|
|
1510
|
+
"docs": {
|
|
1511
|
+
"tags": [],
|
|
1512
|
+
"text": ""
|
|
1513
|
+
},
|
|
1514
|
+
"getter": false,
|
|
1515
|
+
"setter": false,
|
|
1516
|
+
"reflect": false
|
|
1291
1517
|
}
|
|
1292
1518
|
};
|
|
1293
1519
|
}
|
|
@@ -1310,7 +1536,9 @@ export class OcsChat {
|
|
|
1310
1536
|
"isFullscreen": {},
|
|
1311
1537
|
"showNewChatConfirmation": {},
|
|
1312
1538
|
"selectedFiles": {},
|
|
1313
|
-
"isUploadingFiles": {}
|
|
1539
|
+
"isUploadingFiles": {},
|
|
1540
|
+
"isButtonDragging": {},
|
|
1541
|
+
"buttonWasDragged": {}
|
|
1314
1542
|
};
|
|
1315
1543
|
}
|
|
1316
1544
|
static get elementRef() { return "host"; }
|