@hellotext/hellotext 2.3.9 → 2.4.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/dist/hellotext.js +1 -1
- package/dist/webchat-emoji-en.js +1 -0
- package/dist/webchat-emoji-es.js +1 -0
- package/dist/webchat-emoji.js +1 -0
- package/index.d.ts +30 -4
- package/lib/api/webchats.cjs +20 -0
- package/lib/api/webchats.js +20 -0
- package/lib/controllers/mixins/usePopover.cjs +7 -2
- package/lib/controllers/mixins/usePopover.js +7 -2
- package/lib/controllers/webchat/emoji_picker_controller.cjs +49 -10
- package/lib/controllers/webchat/emoji_picker_controller.js +66 -8
- package/lib/controllers/webchat/useBehaviour.cjs +74 -0
- package/lib/controllers/webchat/useBehaviour.js +67 -0
- package/lib/controllers/webchat/useOpeningSequence.cjs +103 -0
- package/lib/controllers/webchat/useOpeningSequence.js +96 -0
- package/lib/controllers/webchat/useTeaser.cjs +163 -0
- package/lib/controllers/webchat/useTeaser.js +156 -0
- package/lib/controllers/webchat_controller.cjs +165 -22
- package/lib/controllers/webchat_controller.js +173 -24
- package/lib/core/configuration/webchat.cjs +117 -42
- package/lib/core/configuration/webchat.js +121 -43
- package/lib/hellotext.cjs +28 -4
- package/lib/hellotext.js +28 -1
- package/lib/models/business.cjs +2 -0
- package/lib/models/business.js +2 -0
- package/lib/models/webchat.cjs +25 -0
- package/lib/models/webchat.js +25 -0
- package/package.json +1 -1
- package/src/api/webchats.js +17 -0
- package/src/controllers/mixins/usePopover.js +4 -2
- package/src/controllers/webchat/emoji_picker_controller.js +51 -9
- package/src/controllers/webchat/useBehaviour.js +81 -0
- package/src/controllers/webchat/useOpeningSequence.js +127 -0
- package/src/controllers/webchat/useTeaser.js +192 -0
- package/src/controllers/webchat_controller.js +187 -23
- package/src/core/configuration/webchat.js +127 -43
- package/src/hellotext.js +32 -4
- package/src/models/business.js +2 -0
- package/src/models/webchat.js +28 -0
|
@@ -23,9 +23,11 @@ import WebchatMessagesAPI from '../api/webchat/messages';
|
|
|
23
23
|
import WebchatChannel from '../channels/webchat_channel';
|
|
24
24
|
import Hellotext from '../hellotext';
|
|
25
25
|
import { Locale } from '../core';
|
|
26
|
-
import { Webchat as WebchatConfiguration,
|
|
27
|
-
import { LogoBuilder } from '../builders/logo_builder';
|
|
26
|
+
import { Webchat as WebchatConfiguration, modes } from '../core/configuration/webchat';
|
|
28
27
|
import { usePopover } from './mixins/usePopover';
|
|
28
|
+
import { useBehaviour } from './webchat/useBehaviour';
|
|
29
|
+
import { useOpeningSequence } from './webchat/useOpeningSequence';
|
|
30
|
+
import { useTeaser } from './webchat/useTeaser';
|
|
29
31
|
var _default = /*#__PURE__*/function (_Controller) {
|
|
30
32
|
_inherits(_default, _Controller);
|
|
31
33
|
var _super = _createSuper(_default);
|
|
@@ -39,6 +41,7 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
39
41
|
this.messagesAPI = new WebchatMessagesAPI(this.idValue);
|
|
40
42
|
this.webChatChannel = new WebchatChannel(this.idValue, Hellotext.session, this.conversationIdValue);
|
|
41
43
|
this.files = [];
|
|
44
|
+
this.messageIds = new Set();
|
|
42
45
|
this.onMessageReceived = this.onMessageReceived.bind(this);
|
|
43
46
|
this.onMessageReaction = this.onMessageReaction.bind(this);
|
|
44
47
|
this.onTypingStart = this.onTypingStart.bind(this);
|
|
@@ -50,30 +53,41 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
50
53
|
}, {
|
|
51
54
|
key: "connect",
|
|
52
55
|
value: function connect() {
|
|
56
|
+
useBehaviour(this);
|
|
53
57
|
usePopover(this);
|
|
54
|
-
this
|
|
55
|
-
this
|
|
58
|
+
useOpeningSequence(this);
|
|
59
|
+
useTeaser(this);
|
|
56
60
|
this.setupFloatingUI({
|
|
57
61
|
trigger: this.triggerTarget,
|
|
58
62
|
popover: this.popoverTarget
|
|
59
63
|
});
|
|
64
|
+
if (this.hasTeaserTarget) {
|
|
65
|
+
this.setupFloatingUI({
|
|
66
|
+
trigger: this.triggerTarget,
|
|
67
|
+
popover: this.teaserTarget,
|
|
68
|
+
strategy: 'absolute'
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
this.setupTeaser();
|
|
72
|
+
this.setupOpeningSequence();
|
|
60
73
|
this.webChatChannel.onMessage(this.onMessageReceived);
|
|
61
74
|
this.webChatChannel.onTypingStart(this.onTypingStart);
|
|
62
75
|
this.webChatChannel.onReaction(this.onMessageReaction);
|
|
63
76
|
this.messagesContainerTarget.addEventListener('scroll', this.onScroll);
|
|
64
|
-
if (!Hellotext.business.features.white_label) {
|
|
65
|
-
this.toolbarTarget.appendChild(LogoBuilder.build());
|
|
66
|
-
}
|
|
67
77
|
if (this.shouldOpenOnMount) {
|
|
68
78
|
this.openValue = true;
|
|
69
79
|
}
|
|
70
80
|
Hellotext.eventEmitter.dispatch('webchat:mounted');
|
|
71
81
|
this.broadcastChannel.addEventListener('message', this.onOutboundMessageSent);
|
|
82
|
+
this.scheduleBehaviourOpen();
|
|
72
83
|
_get(_getPrototypeOf(_default.prototype), "connect", this).call(this);
|
|
73
84
|
}
|
|
74
85
|
}, {
|
|
75
86
|
key: "disconnect",
|
|
76
87
|
value: function disconnect() {
|
|
88
|
+
this.cancelBehaviourOpen();
|
|
89
|
+
this.teardownTeaser();
|
|
90
|
+
this.teardownOpeningSequence();
|
|
77
91
|
this.broadcastChannel.removeEventListener('message', this.onOutboundMessageSent);
|
|
78
92
|
this.messagesContainerTarget.removeEventListener('scroll', this.onScroll);
|
|
79
93
|
|
|
@@ -220,11 +234,12 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
220
234
|
}
|
|
221
235
|
if (attachments) {
|
|
222
236
|
attachments.forEach(attachmentUrl => {
|
|
237
|
+
var _this$messageAttachme;
|
|
223
238
|
var image = this.attachmentImageTarget.cloneNode(true);
|
|
224
239
|
image.removeAttribute('data-hellotext--webchat-target');
|
|
225
240
|
image.src = attachmentUrl;
|
|
226
241
|
image.style.display = 'block';
|
|
227
|
-
|
|
242
|
+
(_this$messageAttachme = this.messageAttachmentsContainer(element)) === null || _this$messageAttachme === void 0 ? void 0 : _this$messageAttachme.appendChild(image);
|
|
228
243
|
});
|
|
229
244
|
}
|
|
230
245
|
element.setAttribute('data-body', body);
|
|
@@ -244,7 +259,7 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
244
259
|
}, {
|
|
245
260
|
key: "onClickOutside",
|
|
246
261
|
value: function onClickOutside(event) {
|
|
247
|
-
if (WebchatConfiguration.
|
|
262
|
+
if (WebchatConfiguration.mode === modes.POPOVER && this.openValue && event.target.nodeType && this.element.contains(event.target) === false) {
|
|
248
263
|
this.openValue = false;
|
|
249
264
|
}
|
|
250
265
|
}
|
|
@@ -259,7 +274,9 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
259
274
|
}, {
|
|
260
275
|
key: "onPopoverOpened",
|
|
261
276
|
value: function onPopoverOpened() {
|
|
277
|
+
var _this$dismissTeaserFo;
|
|
262
278
|
this.popoverTarget.classList.remove(...this.fadeOutClasses);
|
|
279
|
+
(_this$dismissTeaserFo = this.dismissTeaserForSession) === null || _this$dismissTeaserFo === void 0 ? void 0 : _this$dismissTeaserFo.call(this);
|
|
263
280
|
if (!this.onMobile) {
|
|
264
281
|
this.inputTarget.focus();
|
|
265
282
|
}
|
|
@@ -274,6 +291,10 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
274
291
|
}
|
|
275
292
|
Hellotext.eventEmitter.dispatch('webchat:opened');
|
|
276
293
|
localStorage.setItem("hellotext--webchat--".concat(this.idValue), 'opened');
|
|
294
|
+
if (this.messageTeaserValue) {
|
|
295
|
+
this.messageTeaserValue = null;
|
|
296
|
+
}
|
|
297
|
+
this.startOpeningSequence();
|
|
277
298
|
if (this.unreadCounterTarget.style.display === 'none') return;
|
|
278
299
|
this.unreadCounterTarget.style.display = 'none';
|
|
279
300
|
this.unreadCounterTarget.innerText = '0';
|
|
@@ -312,11 +333,15 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
312
333
|
}, {
|
|
313
334
|
key: "onMessageReceived",
|
|
314
335
|
value: function onMessageReceived(message) {
|
|
336
|
+
var _this$hideTeaser;
|
|
315
337
|
var {
|
|
316
338
|
id,
|
|
317
339
|
body,
|
|
318
|
-
attachments
|
|
340
|
+
attachments,
|
|
341
|
+
teaser
|
|
319
342
|
} = message;
|
|
343
|
+
if (!this.claimMessageId(id)) return;
|
|
344
|
+
(_this$hideTeaser = this.hideTeaser) === null || _this$hideTeaser === void 0 ? void 0 : _this$hideTeaser.call(this);
|
|
320
345
|
if (message.carousel) {
|
|
321
346
|
return this.insertCarouselMessage(message);
|
|
322
347
|
}
|
|
@@ -325,13 +350,15 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
325
350
|
var element = this.messageTemplateTarget.cloneNode(true);
|
|
326
351
|
element.style.display = 'flex';
|
|
327
352
|
element.querySelector('[data-body]').innerHTML = div.innerHTML;
|
|
353
|
+
element.setAttribute('data-id', id);
|
|
328
354
|
element.setAttribute('data-hellotext--webchat-target', 'message');
|
|
329
355
|
if (attachments) {
|
|
330
356
|
attachments.forEach(attachmentUrl => {
|
|
357
|
+
var _this$messageAttachme2;
|
|
331
358
|
var image = this.attachmentImageTarget.cloneNode(true);
|
|
332
359
|
image.src = attachmentUrl;
|
|
333
360
|
image.style.display = 'block';
|
|
334
|
-
|
|
361
|
+
(_this$messageAttachme2 = this.messageAttachmentsContainer(element)) === null || _this$messageAttachme2 === void 0 ? void 0 : _this$messageAttachme2.appendChild(image);
|
|
335
362
|
});
|
|
336
363
|
}
|
|
337
364
|
this.clearTypingIndicator();
|
|
@@ -342,13 +369,33 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
342
369
|
element.scrollIntoView({
|
|
343
370
|
behavior: 'smooth'
|
|
344
371
|
});
|
|
372
|
+
this.updateMessageTeaser(teaser);
|
|
345
373
|
if (this.openValue) {
|
|
346
374
|
this.messagesAPI.markAsSeen(id);
|
|
347
375
|
return;
|
|
348
376
|
}
|
|
349
|
-
this.
|
|
350
|
-
|
|
351
|
-
|
|
377
|
+
this.incrementUnreadCounter();
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// TCP broadcasts may deliver the same incoming message twice before Stimulus
|
|
381
|
+
// has connected the appended message target. Claiming the id in memory closes
|
|
382
|
+
// that window, while the target check still drops messages rendered earlier.
|
|
383
|
+
}, {
|
|
384
|
+
key: "claimMessageId",
|
|
385
|
+
value: function claimMessageId(id) {
|
|
386
|
+
var messageTargets = this.messageTargets || [];
|
|
387
|
+
if (this.messageIds.has(id)) return false;
|
|
388
|
+
this.messageIds.add(id);
|
|
389
|
+
return !messageTargets.some(element => element.dataset.id === id);
|
|
390
|
+
}
|
|
391
|
+
}, {
|
|
392
|
+
key: "updateMessageTeaser",
|
|
393
|
+
value: function updateMessageTeaser(teaser) {
|
|
394
|
+
this.messageTeaserValue = teaser;
|
|
395
|
+
if (this.messageTeaserValue && this.hasTeaserTarget) {
|
|
396
|
+
this.teaserTarget.innerHTML = this.messageTeaserValue;
|
|
397
|
+
this.teaserTarget.classList.toggle('invisible', this.openValue);
|
|
398
|
+
}
|
|
352
399
|
}
|
|
353
400
|
}, {
|
|
354
401
|
key: "insertCarouselMessage",
|
|
@@ -356,6 +403,8 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
356
403
|
var _element$querySelecto;
|
|
357
404
|
var html = message.html;
|
|
358
405
|
var element = new DOMParser().parseFromString(html, 'text/html').body.firstElementChild;
|
|
406
|
+
element.setAttribute('data-id', message.id);
|
|
407
|
+
element.setAttribute('data-hellotext--webchat-target', 'message');
|
|
359
408
|
this.clearTypingIndicator();
|
|
360
409
|
this.messagesContainerTarget.appendChild(element);
|
|
361
410
|
element.scrollIntoView({
|
|
@@ -364,13 +413,12 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
364
413
|
Hellotext.eventEmitter.dispatch('webchat:message:received', _objectSpread(_objectSpread({}, message), {}, {
|
|
365
414
|
body: ((_element$querySelecto = element.querySelector('[data-body]')) === null || _element$querySelecto === void 0 ? void 0 : _element$querySelecto.innerText) || ''
|
|
366
415
|
}));
|
|
416
|
+
this.updateMessageTeaser(message.teaser);
|
|
367
417
|
if (this.openValue) {
|
|
368
418
|
this.messagesAPI.markAsSeen(message.id);
|
|
369
419
|
return;
|
|
370
420
|
}
|
|
371
|
-
this.
|
|
372
|
-
var unreadCount = (parseInt(this.unreadCounterTarget.innerText) || 0) + 1;
|
|
373
|
-
this.unreadCounterTarget.innerText = unreadCount > 99 ? '99+' : unreadCount;
|
|
421
|
+
this.incrementUnreadCounter();
|
|
374
422
|
}
|
|
375
423
|
}, {
|
|
376
424
|
key: "resizeInput",
|
|
@@ -389,7 +437,7 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
389
437
|
key: "sendQuickReplyMessage",
|
|
390
438
|
value: function () {
|
|
391
439
|
var _sendQuickReplyMessage = _asyncToGenerator(function* (_ref) {
|
|
392
|
-
var _cardElement$querySel;
|
|
440
|
+
var _this$dismissTeaserFo2, _cardElement$querySel;
|
|
393
441
|
var {
|
|
394
442
|
detail: {
|
|
395
443
|
id,
|
|
@@ -399,6 +447,7 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
399
447
|
cardElement
|
|
400
448
|
}
|
|
401
449
|
} = _ref;
|
|
450
|
+
(_this$dismissTeaserFo2 = this.dismissTeaserForSession) === null || _this$dismissTeaserFo2 === void 0 ? void 0 : _this$dismissTeaserFo2.call(this);
|
|
402
451
|
var formData = new FormData();
|
|
403
452
|
formData.append('message[body]', body);
|
|
404
453
|
formData.append('message[replied_to]', id);
|
|
@@ -406,13 +455,15 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
406
455
|
formData.append('message[button]', buttonId);
|
|
407
456
|
formData.append('session', Hellotext.session);
|
|
408
457
|
formData.append('locale', Locale.toString());
|
|
458
|
+
this.appendOpeningSequenceMessageIds(formData);
|
|
409
459
|
var element = this.buildMessageElement();
|
|
410
460
|
var attachment = (_cardElement$querySel = cardElement.querySelector('img')) === null || _cardElement$querySel === void 0 ? void 0 : _cardElement$querySel.cloneNode(true);
|
|
411
461
|
element.querySelector('[data-body]').innerText = body;
|
|
412
462
|
if (attachment) {
|
|
463
|
+
var _this$messageAttachme3;
|
|
413
464
|
attachment.removeAttribute('width');
|
|
414
465
|
attachment.removeAttribute('height');
|
|
415
|
-
|
|
466
|
+
(_this$messageAttachme3 = this.messageAttachmentsContainer(element)) === null || _this$messageAttachme3 === void 0 ? void 0 : _this$messageAttachme3.appendChild(attachment);
|
|
416
467
|
}
|
|
417
468
|
if (this.typingIndicatorVisible && this.hasTypingIndicatorTarget) {
|
|
418
469
|
this.messagesContainerTarget.insertBefore(element, this.typingIndicatorTarget);
|
|
@@ -441,6 +492,7 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
441
492
|
target: element,
|
|
442
493
|
detail: data.id
|
|
443
494
|
});
|
|
495
|
+
this.clearRevealedOpeningSequenceMessageIds();
|
|
444
496
|
var message = {
|
|
445
497
|
id: data.id,
|
|
446
498
|
body: body,
|
|
@@ -457,11 +509,87 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
457
509
|
}
|
|
458
510
|
return sendQuickReplyMessage;
|
|
459
511
|
}()
|
|
512
|
+
}, {
|
|
513
|
+
key: "sendTeaserQuickReply",
|
|
514
|
+
value: function () {
|
|
515
|
+
var _sendTeaserQuickReply = _asyncToGenerator(function* (event) {
|
|
516
|
+
var _this$dismissTeaserFo3;
|
|
517
|
+
event.preventDefault();
|
|
518
|
+
event.stopPropagation();
|
|
519
|
+
var button = event.currentTarget;
|
|
520
|
+
var value = (button.dataset.value || '').trim();
|
|
521
|
+
var label = [button.dataset.text, button.textContent].map(text => (text || '').trim()).find(text => text.length > 0);
|
|
522
|
+
var text = value || label;
|
|
523
|
+
if (!text) return;
|
|
524
|
+
(_this$dismissTeaserFo3 = this.dismissTeaserForSession) === null || _this$dismissTeaserFo3 === void 0 ? void 0 : _this$dismissTeaserFo3.call(this);
|
|
525
|
+
this.show();
|
|
526
|
+
var buttonType = (button.dataset.type || '').trim() || 'quick_reply';
|
|
527
|
+
var formData = new FormData();
|
|
528
|
+
formData.append('message[body]', text);
|
|
529
|
+
formData.append('session', Hellotext.session);
|
|
530
|
+
formData.append('locale', Locale.toString());
|
|
531
|
+
this.appendOpeningSequenceMessageIds(formData);
|
|
532
|
+
var element = this.buildMessageElement();
|
|
533
|
+
element.querySelector('[data-body]').innerText = text;
|
|
534
|
+
if (this.typingIndicatorVisible && this.hasTypingIndicatorTarget) {
|
|
535
|
+
this.messagesContainerTarget.insertBefore(element, this.typingIndicatorTarget);
|
|
536
|
+
} else {
|
|
537
|
+
this.messagesContainerTarget.appendChild(element);
|
|
538
|
+
}
|
|
539
|
+
element.scrollIntoView({
|
|
540
|
+
behavior: 'smooth'
|
|
541
|
+
});
|
|
542
|
+
this.broadcastChannel.postMessage({
|
|
543
|
+
type: 'message:sent',
|
|
544
|
+
element: element.outerHTML
|
|
545
|
+
});
|
|
546
|
+
if (!this.typingIndicatorVisible) {
|
|
547
|
+
clearTimeout(this.optimisticTypingTimeout);
|
|
548
|
+
this.optimisticTypingTimeout = setTimeout(() => {
|
|
549
|
+
this.showOptimisticTypingIndicator();
|
|
550
|
+
}, this.optimisticTypingIndicatorWaitValue);
|
|
551
|
+
}
|
|
552
|
+
var response = yield this.messagesAPI.create(formData);
|
|
553
|
+
if (response.failed) {
|
|
554
|
+
clearTimeout(this.optimisticTypingTimeout);
|
|
555
|
+
this.broadcastChannel.postMessage({
|
|
556
|
+
type: 'message:failed',
|
|
557
|
+
id: element.id
|
|
558
|
+
});
|
|
559
|
+
return element.classList.add('failed');
|
|
560
|
+
}
|
|
561
|
+
var data = yield response.json();
|
|
562
|
+
element.setAttribute('data-id', data.id);
|
|
563
|
+
this.clearRevealedOpeningSequenceMessageIds();
|
|
564
|
+
Hellotext.eventEmitter.dispatch('webchat:message:sent', {
|
|
565
|
+
id: data.id,
|
|
566
|
+
body: text,
|
|
567
|
+
attachments: [],
|
|
568
|
+
type: 'quick_reply',
|
|
569
|
+
teaser: {
|
|
570
|
+
text: label || text,
|
|
571
|
+
value: value || text,
|
|
572
|
+
type: buttonType
|
|
573
|
+
}
|
|
574
|
+
});
|
|
575
|
+
if (data.conversation && data.conversation !== this.conversationIdValue) {
|
|
576
|
+
this.conversationIdValue = data.conversation;
|
|
577
|
+
this.webChatChannel.updateSubscriptionWith(this.conversationIdValue);
|
|
578
|
+
}
|
|
579
|
+
if (this.typingIndicatorVisible) {
|
|
580
|
+
this.resetTypingIndicatorTimer();
|
|
581
|
+
}
|
|
582
|
+
});
|
|
583
|
+
function sendTeaserQuickReply(_x2) {
|
|
584
|
+
return _sendTeaserQuickReply.apply(this, arguments);
|
|
585
|
+
}
|
|
586
|
+
return sendTeaserQuickReply;
|
|
587
|
+
}()
|
|
460
588
|
}, {
|
|
461
589
|
key: "sendMessage",
|
|
462
590
|
value: function () {
|
|
463
591
|
var _sendMessage = _asyncToGenerator(function* (e) {
|
|
464
|
-
var
|
|
592
|
+
var _this$dismissTeaserFo4;
|
|
465
593
|
var message = {
|
|
466
594
|
body: this.inputTarget.value,
|
|
467
595
|
attachments: this.files
|
|
@@ -472,6 +600,8 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
472
600
|
}
|
|
473
601
|
return;
|
|
474
602
|
}
|
|
603
|
+
(_this$dismissTeaserFo4 = this.dismissTeaserForSession) === null || _this$dismissTeaserFo4 === void 0 ? void 0 : _this$dismissTeaserFo4.call(this);
|
|
604
|
+
var formData = new FormData();
|
|
475
605
|
if (this.inputTarget.value.trim().length > 0) {
|
|
476
606
|
formData.append('message[body]', this.inputTarget.value);
|
|
477
607
|
} else {
|
|
@@ -482,6 +612,7 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
482
612
|
});
|
|
483
613
|
formData.append('session', Hellotext.session);
|
|
484
614
|
formData.append('locale', Locale.toString());
|
|
615
|
+
this.appendOpeningSequenceMessageIds(formData);
|
|
485
616
|
var element = this.buildMessageElement();
|
|
486
617
|
if (this.inputTarget.value.trim().length > 0) {
|
|
487
618
|
element.querySelector('[data-body]').innerText = this.inputTarget.value;
|
|
@@ -491,7 +622,8 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
491
622
|
var attachments = this.attachmentContainerTarget.querySelectorAll('img');
|
|
492
623
|
if (attachments.length > 0) {
|
|
493
624
|
attachments.forEach(attachment => {
|
|
494
|
-
|
|
625
|
+
var _this$messageAttachme4;
|
|
626
|
+
(_this$messageAttachme4 = this.messageAttachmentsContainer(element)) === null || _this$messageAttachme4 === void 0 ? void 0 : _this$messageAttachme4.appendChild(attachment.cloneNode(true));
|
|
495
627
|
});
|
|
496
628
|
}
|
|
497
629
|
|
|
@@ -538,6 +670,7 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
538
670
|
var data = yield response.json();
|
|
539
671
|
element.setAttribute('data-id', data.id);
|
|
540
672
|
message.id = data.id;
|
|
673
|
+
this.clearRevealedOpeningSequenceMessageIds();
|
|
541
674
|
Hellotext.eventEmitter.dispatch('webchat:message:sent', message);
|
|
542
675
|
if (data.conversation !== this.conversationIdValue) {
|
|
543
676
|
this.conversationIdValue = data.conversation;
|
|
@@ -550,7 +683,7 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
550
683
|
}
|
|
551
684
|
this.attachmentContainerTarget.style.display = '';
|
|
552
685
|
});
|
|
553
|
-
function sendMessage(
|
|
686
|
+
function sendMessage(_x3) {
|
|
554
687
|
return _sendMessage.apply(this, arguments);
|
|
555
688
|
}
|
|
556
689
|
return sendMessage;
|
|
@@ -566,6 +699,18 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
566
699
|
element.setAttribute('data-hellotext--webchat-target', 'message');
|
|
567
700
|
return element;
|
|
568
701
|
}
|
|
702
|
+
}, {
|
|
703
|
+
key: "messageAttachmentsContainer",
|
|
704
|
+
value: function messageAttachmentsContainer(element) {
|
|
705
|
+
return element.querySelector('[data-attachments-container], [data-attachment-container]');
|
|
706
|
+
}
|
|
707
|
+
}, {
|
|
708
|
+
key: "incrementUnreadCounter",
|
|
709
|
+
value: function incrementUnreadCounter() {
|
|
710
|
+
this.unreadCounterTarget.style.display = 'flex';
|
|
711
|
+
var unreadCount = (parseInt(this.unreadCounterTarget.innerText) || 0) + 1;
|
|
712
|
+
this.unreadCounterTarget.innerText = Math.min(unreadCount, 9);
|
|
713
|
+
}
|
|
569
714
|
}, {
|
|
570
715
|
key: "openAttachment",
|
|
571
716
|
value: function openAttachment() {
|
|
@@ -732,8 +877,12 @@ _default.values = {
|
|
|
732
877
|
optimisticTypingIndicatorWait: {
|
|
733
878
|
type: Number,
|
|
734
879
|
default: 1000
|
|
735
|
-
}
|
|
880
|
+
},
|
|
881
|
+
// 1 second,
|
|
882
|
+
teaser: Object,
|
|
883
|
+
messageTeaser: String,
|
|
884
|
+
behaviour: Object
|
|
736
885
|
};
|
|
737
886
|
_default.classes = ['fadeOut'];
|
|
738
|
-
_default.targets = ['trigger', 'popover', 'input', 'attachmentInput', 'attachmentButton', 'errorMessageContainer', 'attachmentTemplate', 'attachmentContainer', 'attachment', 'messageTemplate', 'messagesContainer', 'title', 'attachmentImage', 'footer', 'toolbar', 'message', 'unreadCounter', 'typingIndicator', 'typingIndicatorTemplate'];
|
|
887
|
+
_default.targets = ['trigger', 'popover', 'input', 'attachmentInput', 'attachmentButton', 'errorMessageContainer', 'attachmentTemplate', 'attachmentContainer', 'attachment', 'messageTemplate', 'messagesContainer', 'title', 'attachmentImage', 'footer', 'toolbar', 'message', 'unreadCounter', 'typingIndicator', 'typingIndicatorTemplate', 'teaser', 'openingSequence', 'openingSequenceMessage'];
|
|
739
888
|
export { _default as default };
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.
|
|
6
|
+
exports.modes = exports.Webchat = void 0;
|
|
7
7
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
8
8
|
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
|
|
9
9
|
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
|
|
@@ -39,13 +39,13 @@ const strategies = {
|
|
|
39
39
|
};
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
|
-
* @typedef {'modal' | 'popover'}
|
|
42
|
+
* @typedef {'modal' | 'popover'} Mode
|
|
43
43
|
*/
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
|
-
* @enum {
|
|
46
|
+
* @enum {Mode}
|
|
47
47
|
*/
|
|
48
|
-
const
|
|
48
|
+
const modes = {
|
|
49
49
|
MODAL: 'modal',
|
|
50
50
|
POPOVER: 'popover'
|
|
51
51
|
};
|
|
@@ -57,6 +57,20 @@ const behaviors = {
|
|
|
57
57
|
* @property {string} typography - The typography style (e.g., font family).
|
|
58
58
|
*/
|
|
59
59
|
|
|
60
|
+
/**
|
|
61
|
+
* @typedef {Object} Appearance
|
|
62
|
+
* @property {Object} [header] - Header appearance overrides.
|
|
63
|
+
* @property {string} [header.name] - Business name shown in the webchat header.
|
|
64
|
+
* @property {Object} [launcher] - Launcher appearance overrides.
|
|
65
|
+
* @property {string} [launcher.iconUrl] - Image URL used for the launcher icon.
|
|
66
|
+
*/
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @typedef {Object} WhatsApp
|
|
70
|
+
* @property {string} [number] - WhatsApp number used by the handoff configuration.
|
|
71
|
+
* @property {boolean} [restrictToChannel] - Whether handoff should be restricted to the configured channel.
|
|
72
|
+
*/
|
|
73
|
+
|
|
60
74
|
/**
|
|
61
75
|
* @class Webchat
|
|
62
76
|
* @classdesc
|
|
@@ -64,13 +78,14 @@ const behaviors = {
|
|
|
64
78
|
* @property {String} id - the id of the webchat.
|
|
65
79
|
* @property {String} container - the container to append the webchat to, defaults to 'body'
|
|
66
80
|
* @property {Placement} placement - the placement of the webchat within the container, defaults to "bottom-right".
|
|
67
|
-
* @property {
|
|
68
|
-
* @property {
|
|
69
|
-
* @property {Behaviour} behaviour - the behaviour of the webchat, defaults to 'popover'.
|
|
81
|
+
* @property {Mode} mode - how the webchat behaves while open, defaults to 'popover'.
|
|
82
|
+
* @property {Object} behaviour - runtime opening behaviour for the webchat.
|
|
70
83
|
* @property {Style} style - the style of the webchat.
|
|
84
|
+
* @property {Appearance} appearance - appearance overrides.
|
|
85
|
+
* @property {WhatsApp} whatsapp - WhatsApp handoff overrides.
|
|
71
86
|
* @property {Strategy} strategy - the strategy used to position the webchat. Defaults to 'absolute'
|
|
72
87
|
*/
|
|
73
|
-
exports.
|
|
88
|
+
exports.modes = modes;
|
|
74
89
|
let Webchat = /*#__PURE__*/function () {
|
|
75
90
|
function Webchat() {
|
|
76
91
|
_classCallCheck(this, Webchat);
|
|
@@ -94,36 +109,6 @@ let Webchat = /*#__PURE__*/function () {
|
|
|
94
109
|
}
|
|
95
110
|
this._placement = value;
|
|
96
111
|
}
|
|
97
|
-
}, {
|
|
98
|
-
key: "classes",
|
|
99
|
-
get: function () {
|
|
100
|
-
if (typeof this._classes === 'string') {
|
|
101
|
-
return this._classes.split(',').map(c => c.trim());
|
|
102
|
-
} else {
|
|
103
|
-
return this._classes;
|
|
104
|
-
}
|
|
105
|
-
},
|
|
106
|
-
set: function (value) {
|
|
107
|
-
if (!Array.isArray(value) && typeof value !== 'string') {
|
|
108
|
-
throw new Error('classes must be an array or a string');
|
|
109
|
-
}
|
|
110
|
-
this._classes = value;
|
|
111
|
-
}
|
|
112
|
-
}, {
|
|
113
|
-
key: "triggerClasses",
|
|
114
|
-
get: function () {
|
|
115
|
-
if (typeof this._triggerClasses === 'string') {
|
|
116
|
-
return this._triggerClasses.split(',').map(c => c.trim());
|
|
117
|
-
} else {
|
|
118
|
-
return this._triggerClasses;
|
|
119
|
-
}
|
|
120
|
-
},
|
|
121
|
-
set: function (value) {
|
|
122
|
-
if (!Array.isArray(value) && typeof value !== 'string') {
|
|
123
|
-
throw new Error('triggerClasses must be an array or a string');
|
|
124
|
-
}
|
|
125
|
-
this._triggerClasses = value;
|
|
126
|
-
}
|
|
127
112
|
}, {
|
|
128
113
|
key: "id",
|
|
129
114
|
get: function () {
|
|
@@ -159,17 +144,100 @@ let Webchat = /*#__PURE__*/function () {
|
|
|
159
144
|
});
|
|
160
145
|
this._style = value;
|
|
161
146
|
}
|
|
147
|
+
}, {
|
|
148
|
+
key: "appearance",
|
|
149
|
+
get: function () {
|
|
150
|
+
return this._appearance;
|
|
151
|
+
},
|
|
152
|
+
set: function (value) {
|
|
153
|
+
if (!this.isPlainObject(value)) {
|
|
154
|
+
throw new Error('Appearance must be an object');
|
|
155
|
+
}
|
|
156
|
+
Object.entries(value).forEach(([key, nestedValue]) => {
|
|
157
|
+
if (!['header', 'launcher'].includes(key)) {
|
|
158
|
+
throw new Error(`Invalid appearance property: ${key}`);
|
|
159
|
+
}
|
|
160
|
+
if (!this.isPlainObject(nestedValue)) {
|
|
161
|
+
throw new Error(`Appearance ${key} must be an object`);
|
|
162
|
+
}
|
|
163
|
+
Object.entries(nestedValue).forEach(([nestedKey, propertyValue]) => {
|
|
164
|
+
if (key === 'header' && nestedKey !== 'name') {
|
|
165
|
+
throw new Error(`Invalid appearance header property: ${nestedKey}`);
|
|
166
|
+
}
|
|
167
|
+
if (key === 'launcher' && nestedKey !== 'iconUrl') {
|
|
168
|
+
throw new Error(`Invalid appearance launcher property: ${nestedKey}`);
|
|
169
|
+
}
|
|
170
|
+
if (propertyValue == null) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if (typeof propertyValue !== 'string') {
|
|
174
|
+
throw new Error(`Invalid appearance ${key}.${nestedKey} value: ${propertyValue}`);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
this._appearance = value;
|
|
179
|
+
}
|
|
180
|
+
}, {
|
|
181
|
+
key: "whatsapp",
|
|
182
|
+
get: function () {
|
|
183
|
+
return this._whatsapp;
|
|
184
|
+
},
|
|
185
|
+
set: function (value) {
|
|
186
|
+
if (!this.isPlainObject(value)) {
|
|
187
|
+
throw new Error('WhatsApp must be an object');
|
|
188
|
+
}
|
|
189
|
+
Object.entries(value).forEach(([key, nestedValue]) => {
|
|
190
|
+
if (!['number', 'restrictToChannel'].includes(key)) {
|
|
191
|
+
throw new Error(`Invalid WhatsApp property: ${key}`);
|
|
192
|
+
}
|
|
193
|
+
if (nestedValue == null) {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (key === 'number' && typeof nestedValue !== 'string') {
|
|
197
|
+
throw new Error(`Invalid WhatsApp number value: ${nestedValue}`);
|
|
198
|
+
}
|
|
199
|
+
if (key === 'restrictToChannel' && typeof nestedValue !== 'boolean') {
|
|
200
|
+
throw new Error(`Invalid WhatsApp restrictToChannel value: ${nestedValue}`);
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
this._whatsapp = value;
|
|
204
|
+
}
|
|
205
|
+
}, {
|
|
206
|
+
key: "mode",
|
|
207
|
+
get: function () {
|
|
208
|
+
return this._mode;
|
|
209
|
+
},
|
|
210
|
+
set: function (value) {
|
|
211
|
+
if (!Object.values(modes).includes(value)) {
|
|
212
|
+
throw new Error(`Invalid mode value: ${value}`);
|
|
213
|
+
}
|
|
214
|
+
this._mode = value;
|
|
215
|
+
}
|
|
162
216
|
}, {
|
|
163
217
|
key: "behaviour",
|
|
164
218
|
get: function () {
|
|
165
219
|
return this._behaviour;
|
|
166
220
|
},
|
|
167
221
|
set: function (value) {
|
|
168
|
-
if (
|
|
222
|
+
if (value == null) {
|
|
223
|
+
this._behaviour = value;
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
if (typeof value !== 'object' || Array.isArray(value)) {
|
|
169
227
|
throw new Error(`Invalid behaviour value: ${value}`);
|
|
170
228
|
}
|
|
171
229
|
this._behaviour = value;
|
|
172
230
|
}
|
|
231
|
+
}, {
|
|
232
|
+
key: "hasBehaviourOverride",
|
|
233
|
+
get: function () {
|
|
234
|
+
return this._hasBehaviourOverride;
|
|
235
|
+
}
|
|
236
|
+
}, {
|
|
237
|
+
key: "behaviourOverride",
|
|
238
|
+
set: function (value) {
|
|
239
|
+
this._hasBehaviourOverride = !!value;
|
|
240
|
+
}
|
|
173
241
|
}, {
|
|
174
242
|
key: "strategy",
|
|
175
243
|
get: function () {
|
|
@@ -199,6 +267,11 @@ let Webchat = /*#__PURE__*/function () {
|
|
|
199
267
|
value: function isHexOrRgba(value) {
|
|
200
268
|
return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(value) || /^rgba?\(\s*\d{1,3},\s*\d{1,3},\s*\d{1,3},?\s*(0|1|0?\.\d+)?\s*\)$/.test(value);
|
|
201
269
|
}
|
|
270
|
+
}, {
|
|
271
|
+
key: "isPlainObject",
|
|
272
|
+
value: function isPlainObject(value) {
|
|
273
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
274
|
+
}
|
|
202
275
|
}]);
|
|
203
276
|
return Webchat;
|
|
204
277
|
}();
|
|
@@ -206,8 +279,10 @@ exports.Webchat = Webchat;
|
|
|
206
279
|
Webchat._id = void 0;
|
|
207
280
|
Webchat._container = 'body';
|
|
208
281
|
Webchat._placement = 'bottom-right';
|
|
209
|
-
Webchat._classes = [];
|
|
210
|
-
Webchat._triggerClasses = [];
|
|
211
282
|
Webchat._style = {};
|
|
212
|
-
Webchat.
|
|
283
|
+
Webchat._appearance = {};
|
|
284
|
+
Webchat._whatsapp = {};
|
|
285
|
+
Webchat._mode = modes.POPOVER;
|
|
286
|
+
Webchat._behaviour = null;
|
|
287
|
+
Webchat._hasBehaviourOverride = false;
|
|
213
288
|
Webchat._strategy = null;
|