@hellotext/hellotext 2.4.4 → 2.4.5
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/lib/api/webchat/messages.cjs +8 -0
- package/lib/api/webchat/messages.js +8 -0
- package/lib/channels/application_channel.cjs +143 -10
- package/lib/channels/application_channel.js +143 -10
- package/lib/channels/webchat_channel.cjs +57 -0
- package/lib/channels/webchat_channel.js +57 -0
- package/lib/controllers/webchat_controller.cjs +143 -22
- package/lib/controllers/webchat_controller.js +148 -18
- package/package.json +1 -1
- package/src/api/webchat/messages.js +7 -0
- package/src/channels/application_channel.js +152 -9
- package/src/channels/webchat_channel.js +61 -1
- package/src/controllers/webchat_controller.js +157 -21
|
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.default = void 0;
|
|
7
7
|
var _dom = require("@floating-ui/dom");
|
|
8
8
|
var _stimulus = require("@hotwired/stimulus");
|
|
9
|
-
var
|
|
9
|
+
var _messages2 = _interopRequireDefault(require("../api/webchat/messages"));
|
|
10
10
|
var _webchat_channel = _interopRequireDefault(require("../channels/webchat_channel"));
|
|
11
11
|
var _hellotext = _interopRequireDefault(require("../hellotext"));
|
|
12
12
|
var _core = require("../core");
|
|
@@ -35,6 +35,7 @@ const MESSAGE_TIMESTAMP_FORMAT_OPTIONS = {
|
|
|
35
35
|
hour: 'numeric',
|
|
36
36
|
minute: '2-digit'
|
|
37
37
|
};
|
|
38
|
+
const MOBILE_USER_AGENT_PATTERN = /Android|iPhone|iPad|iPod/i;
|
|
38
39
|
const SCROLL_ISOLATION_EVENT_OPTIONS = {
|
|
39
40
|
capture: true,
|
|
40
41
|
passive: true
|
|
@@ -49,17 +50,23 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
49
50
|
_createClass(_default, [{
|
|
50
51
|
key: "initialize",
|
|
51
52
|
value: function initialize() {
|
|
52
|
-
this.messagesAPI = new
|
|
53
|
+
this.messagesAPI = new _messages2.default(this.idValue);
|
|
53
54
|
this.webChatChannel = new _webchat_channel.default(this.idValue, _hellotext.default.session, this.conversationIdValue);
|
|
54
55
|
this.files = [];
|
|
55
56
|
this.messageIds = new Set();
|
|
57
|
+
this.catchUpAfterMessageId = null;
|
|
58
|
+
this.fetchingCatchUpMessages = false;
|
|
56
59
|
this.onMessageReceived = this.onMessageReceived.bind(this);
|
|
57
60
|
this.onMessageReaction = this.onMessageReaction.bind(this);
|
|
58
61
|
this.onTypingStart = this.onTypingStart.bind(this);
|
|
62
|
+
this.captureCatchUpCursor = this.captureCatchUpCursor.bind(this);
|
|
63
|
+
this.catchUpMessages = this.catchUpMessages.bind(this);
|
|
59
64
|
this.onScroll = this.onScroll.bind(this);
|
|
60
65
|
this.onOutboundMessageSent = this.onOutboundMessageSent.bind(this);
|
|
61
66
|
this.closePopoverOnEscape = this.closePopoverOnEscape.bind(this);
|
|
62
67
|
this.broadcastChannel = new BroadcastChannel(`hellotext--webchat--${this.idValue}`);
|
|
68
|
+
this.webChatChannel.onDisconnect(this.captureCatchUpCursor);
|
|
69
|
+
this.webChatChannel.onReconnect(this.catchUpMessages);
|
|
63
70
|
_get(_getPrototypeOf(_default.prototype), "initialize", this).call(this);
|
|
64
71
|
}
|
|
65
72
|
}, {
|
|
@@ -261,7 +268,12 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
261
268
|
const div = document.createElement('div');
|
|
262
269
|
div.innerHTML = body;
|
|
263
270
|
const element = this.messageTemplateTarget.cloneNode(true);
|
|
271
|
+
element.classList.add('hellotext--webchat-message');
|
|
264
272
|
element.setAttribute('data-hellotext--webchat-target', 'message');
|
|
273
|
+
element.setAttribute('data-id', message.id);
|
|
274
|
+
if (createdAt) {
|
|
275
|
+
element.setAttribute('data-created-at', createdAt);
|
|
276
|
+
}
|
|
265
277
|
element.style.removeProperty('display');
|
|
266
278
|
element.querySelector('[data-body]').innerHTML = div.innerHTML;
|
|
267
279
|
if (message.state === 'received') {
|
|
@@ -331,7 +343,7 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
331
343
|
this.popoverTarget.classList.remove(...this.fadeOutClasses);
|
|
332
344
|
(_this$dismissTeaserFo = this.dismissTeaserForSession) === null || _this$dismissTeaserFo === void 0 ? void 0 : _this$dismissTeaserFo.call(this);
|
|
333
345
|
if (!this.onMobile) {
|
|
334
|
-
this.
|
|
346
|
+
this.focusComposeInput();
|
|
335
347
|
}
|
|
336
348
|
if (!this.scrolled) {
|
|
337
349
|
requestAnimationFrame(() => {
|
|
@@ -386,7 +398,7 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
386
398
|
}
|
|
387
399
|
}, {
|
|
388
400
|
key: "onMessageReceived",
|
|
389
|
-
value: function onMessageReceived(message) {
|
|
401
|
+
value: function onMessageReceived(message, options = {}) {
|
|
390
402
|
var _this$hideTeaser;
|
|
391
403
|
const {
|
|
392
404
|
id,
|
|
@@ -398,15 +410,17 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
398
410
|
if (!this.claimMessageId(id)) return;
|
|
399
411
|
(_this$hideTeaser = this.hideTeaser) === null || _this$hideTeaser === void 0 ? void 0 : _this$hideTeaser.call(this);
|
|
400
412
|
if (message.carousel) {
|
|
401
|
-
return this.insertCarouselMessage(message);
|
|
413
|
+
return this.insertCarouselMessage(message, options);
|
|
402
414
|
}
|
|
403
415
|
const div = document.createElement('div');
|
|
404
416
|
div.innerHTML = body;
|
|
405
417
|
const element = this.messageTemplateTarget.cloneNode(true);
|
|
418
|
+
element.classList.add('hellotext--webchat-message');
|
|
406
419
|
element.style.display = 'flex';
|
|
407
420
|
element.querySelector('[data-body]').innerHTML = div.innerHTML;
|
|
408
421
|
element.setAttribute('data-id', id);
|
|
409
422
|
element.setAttribute('data-hellotext--webchat-target', 'message');
|
|
423
|
+
this.setMessageCreatedAt(element, createdAt);
|
|
410
424
|
this.localizeMessageTimestamp(element.querySelector('[data-message-timestamp]'), createdAt);
|
|
411
425
|
if (attachments) {
|
|
412
426
|
attachments.forEach(attachmentUrl => {
|
|
@@ -418,14 +432,16 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
418
432
|
});
|
|
419
433
|
}
|
|
420
434
|
this.clearTypingIndicator();
|
|
421
|
-
this.
|
|
435
|
+
this.insertMessageElement(element);
|
|
422
436
|
_hellotext.default.eventEmitter.dispatch('webchat:message:received', {
|
|
423
437
|
...message,
|
|
424
438
|
body: element.querySelector('[data-body]').innerText
|
|
425
439
|
});
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
440
|
+
if (options.scroll !== false) {
|
|
441
|
+
element.scrollIntoView({
|
|
442
|
+
behavior: 'smooth'
|
|
443
|
+
});
|
|
444
|
+
}
|
|
429
445
|
this.updateMessageTeaser(teaser);
|
|
430
446
|
if (this.openValue) {
|
|
431
447
|
this.messagesAPI.markAsSeen(id);
|
|
@@ -445,6 +461,70 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
445
461
|
this.messageIds.add(id);
|
|
446
462
|
return !messageTargets.some(element => element.dataset.id === id);
|
|
447
463
|
}
|
|
464
|
+
}, {
|
|
465
|
+
key: "captureCatchUpCursor",
|
|
466
|
+
value: function captureCatchUpCursor() {
|
|
467
|
+
this.catchUpAfterMessageId = this.lastRenderedMessageId;
|
|
468
|
+
}
|
|
469
|
+
}, {
|
|
470
|
+
key: "catchUpMessages",
|
|
471
|
+
value: async function catchUpMessages() {
|
|
472
|
+
const afterId = this.catchUpAfterMessageId;
|
|
473
|
+
if (!afterId || this.fetchingCatchUpMessages) return;
|
|
474
|
+
this.fetchingCatchUpMessages = true;
|
|
475
|
+
try {
|
|
476
|
+
const response = await this.messagesAPI.catchUp(afterId);
|
|
477
|
+
const {
|
|
478
|
+
messages = []
|
|
479
|
+
} = await response.json();
|
|
480
|
+
messages.forEach(message => this.onMessageReceived(message, {
|
|
481
|
+
scroll: false
|
|
482
|
+
}));
|
|
483
|
+
this.catchUpAfterMessageId = this.lastRenderedMessageId;
|
|
484
|
+
} finally {
|
|
485
|
+
this.fetchingCatchUpMessages = false;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}, {
|
|
489
|
+
key: "lastRenderedMessageId",
|
|
490
|
+
get: function () {
|
|
491
|
+
var _messages;
|
|
492
|
+
const messages = this.persistedMessageElements;
|
|
493
|
+
return ((_messages = messages[messages.length - 1]) === null || _messages === void 0 ? void 0 : _messages.dataset.id) || null;
|
|
494
|
+
}
|
|
495
|
+
}, {
|
|
496
|
+
key: "persistedMessageElements",
|
|
497
|
+
get: function () {
|
|
498
|
+
return Array.from(this.messagesContainerTarget.querySelectorAll('.hellotext--webchat-message[data-id]'));
|
|
499
|
+
}
|
|
500
|
+
}, {
|
|
501
|
+
key: "setMessageCreatedAt",
|
|
502
|
+
value: function setMessageCreatedAt(element, createdAt) {
|
|
503
|
+
if (createdAt) {
|
|
504
|
+
element.setAttribute('data-created-at', createdAt);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}, {
|
|
508
|
+
key: "insertMessageElement",
|
|
509
|
+
value: function insertMessageElement(element) {
|
|
510
|
+
const nextElement = this.nextMessageElementFor(element);
|
|
511
|
+
if (nextElement) {
|
|
512
|
+
this.messagesContainerTarget.insertBefore(element, nextElement);
|
|
513
|
+
} else {
|
|
514
|
+
this.messagesContainerTarget.appendChild(element);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}, {
|
|
518
|
+
key: "nextMessageElementFor",
|
|
519
|
+
value: function nextMessageElementFor(element) {
|
|
520
|
+
const createdAt = Date.parse(element.dataset.createdAt);
|
|
521
|
+
if (Number.isNaN(createdAt)) return null;
|
|
522
|
+
return this.persistedMessageElements.find(messageElement => {
|
|
523
|
+
if (messageElement === element) return false;
|
|
524
|
+
const messageCreatedAt = Date.parse(messageElement.dataset.createdAt);
|
|
525
|
+
return !Number.isNaN(messageCreatedAt) && messageCreatedAt > createdAt;
|
|
526
|
+
});
|
|
527
|
+
}
|
|
448
528
|
}, {
|
|
449
529
|
key: "updateMessageTeaser",
|
|
450
530
|
value: function updateMessageTeaser(teaser) {
|
|
@@ -459,18 +539,23 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
459
539
|
}
|
|
460
540
|
}, {
|
|
461
541
|
key: "insertCarouselMessage",
|
|
462
|
-
value: function insertCarouselMessage(message) {
|
|
542
|
+
value: function insertCarouselMessage(message, options = {}) {
|
|
463
543
|
var _element$querySelecto;
|
|
464
544
|
const html = message.html;
|
|
545
|
+
const createdAt = message.created_at || message.createdAt;
|
|
465
546
|
const element = new DOMParser().parseFromString(html, 'text/html').body.firstElementChild;
|
|
547
|
+
element.classList.add('hellotext--webchat-message');
|
|
466
548
|
element.setAttribute('data-id', message.id);
|
|
467
549
|
element.setAttribute('data-hellotext--webchat-target', 'message');
|
|
550
|
+
this.setMessageCreatedAt(element, createdAt);
|
|
468
551
|
this.localizeMessageTimestamps(element);
|
|
469
552
|
this.clearTypingIndicator();
|
|
470
|
-
this.
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
553
|
+
this.insertMessageElement(element);
|
|
554
|
+
if (options.scroll !== false) {
|
|
555
|
+
element.scrollIntoView({
|
|
556
|
+
behavior: 'smooth'
|
|
557
|
+
});
|
|
558
|
+
}
|
|
474
559
|
_hellotext.default.eventEmitter.dispatch('webchat:message:received', {
|
|
475
560
|
...message,
|
|
476
561
|
body: ((_element$querySelecto = element.querySelector('[data-body]')) === null || _element$querySelecto === void 0 ? void 0 : _element$querySelecto.innerText) || ''
|
|
@@ -689,7 +774,7 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
689
774
|
this.attachmentContainerTarget.innerHTML = '';
|
|
690
775
|
this.attachmentContainerTarget.style.display = 'none';
|
|
691
776
|
this.errorMessageContainerTarget.style.display = 'none';
|
|
692
|
-
this.
|
|
777
|
+
this.focusComposeInput();
|
|
693
778
|
|
|
694
779
|
// Set up optimistic typing indicator BEFORE making the API call
|
|
695
780
|
// This prevents race conditions with server responses
|
|
@@ -742,12 +827,10 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
742
827
|
} = event;
|
|
743
828
|
const ignoredSelector = ['button', 'a', 'input', 'textarea', 'select', 'label', '[role="button"]', 'em-emoji-picker', '[data-hellotext--webchat--emoji-target~="popover"]', '[data-controller~="hellotext--webchat--emoji"]'].join(', ');
|
|
744
829
|
if (!this.hasInputTarget || target.closest(ignoredSelector)) return;
|
|
830
|
+
if (!this.focusComposeInput({
|
|
831
|
+
moveCursorToEnd: true
|
|
832
|
+
})) return;
|
|
745
833
|
event.preventDefault();
|
|
746
|
-
this.inputTarget.focus();
|
|
747
|
-
if (typeof this.inputTarget.selectionStart === 'number') {
|
|
748
|
-
const position = this.inputTarget.value.length;
|
|
749
|
-
this.inputTarget.setSelectionRange(position, position);
|
|
750
|
-
}
|
|
751
834
|
}
|
|
752
835
|
}, {
|
|
753
836
|
key: "closePopoverFromHeader",
|
|
@@ -896,7 +979,7 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
896
979
|
this.files = [...this.files, ...newFiles];
|
|
897
980
|
this.errorMessageContainerTarget.innerText = '';
|
|
898
981
|
newFiles.forEach(file => this.createAttachmentElement(file));
|
|
899
|
-
this.
|
|
982
|
+
this.focusComposeInput();
|
|
900
983
|
}
|
|
901
984
|
}, {
|
|
902
985
|
key: "createAttachmentElement",
|
|
@@ -931,7 +1014,7 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
931
1014
|
this.files = this.files.filter(file => file.name !== attachment.dataset.name);
|
|
932
1015
|
this.attachmentInputTarget.value = '';
|
|
933
1016
|
attachment.remove();
|
|
934
|
-
this.
|
|
1017
|
+
this.focusComposeInput();
|
|
935
1018
|
}
|
|
936
1019
|
}, {
|
|
937
1020
|
key: "attachmentTargetDisconnected",
|
|
@@ -960,7 +1043,22 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
960
1043
|
const end = this.inputTarget.selectionEnd;
|
|
961
1044
|
this.inputTarget.value = value.slice(0, start) + emoji + value.slice(end);
|
|
962
1045
|
this.inputTarget.selectionStart = this.inputTarget.selectionEnd = start + emoji.length;
|
|
1046
|
+
this.focusComposeInput();
|
|
1047
|
+
}
|
|
1048
|
+
}, {
|
|
1049
|
+
key: "focusComposeInput",
|
|
1050
|
+
value: function focusComposeInput({
|
|
1051
|
+
moveCursorToEnd = false
|
|
1052
|
+
} = {}) {
|
|
1053
|
+
if (!this.shouldAutofocusCompose) return false;
|
|
1054
|
+
if (this.hasInputTarget === false) return false;
|
|
1055
|
+
if (this.hasInputTarget === undefined && !this.inputTarget) return false;
|
|
963
1056
|
this.inputTarget.focus();
|
|
1057
|
+
if (moveCursorToEnd && typeof this.inputTarget.selectionStart === 'number') {
|
|
1058
|
+
const position = this.inputTarget.value.length;
|
|
1059
|
+
this.inputTarget.setSelectionRange(position, position);
|
|
1060
|
+
}
|
|
1061
|
+
return true;
|
|
964
1062
|
}
|
|
965
1063
|
}, {
|
|
966
1064
|
key: "byteToMegabyte",
|
|
@@ -979,9 +1077,32 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
979
1077
|
get: function () {
|
|
980
1078
|
return localStorage.getItem(`hellotext--webchat--${this.idValue}`) === 'opened' && !this.onMobile;
|
|
981
1079
|
}
|
|
1080
|
+
}, {
|
|
1081
|
+
key: "shouldAutofocusCompose",
|
|
1082
|
+
get: function () {
|
|
1083
|
+
return !this.usesVirtualKeyboard;
|
|
1084
|
+
}
|
|
1085
|
+
}, {
|
|
1086
|
+
key: "usesVirtualKeyboard",
|
|
1087
|
+
get: function () {
|
|
1088
|
+
var _navigator$userAgentD;
|
|
1089
|
+
if (typeof navigator === 'undefined') return false;
|
|
1090
|
+
const userAgent = navigator.userAgent || '';
|
|
1091
|
+
const isIPadOS = navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1;
|
|
1092
|
+
const isMobileUserAgent = MOBILE_USER_AGENT_PATTERN.test(userAgent);
|
|
1093
|
+
const isUserAgentDataMobile = ((_navigator$userAgentD = navigator.userAgentData) === null || _navigator$userAgentD === void 0 ? void 0 : _navigator$userAgentD.mobile) === true;
|
|
1094
|
+
return isMobileUserAgent || isIPadOS || isUserAgentDataMobile || this.hasTouchOnlyPointer;
|
|
1095
|
+
}
|
|
1096
|
+
}, {
|
|
1097
|
+
key: "hasTouchOnlyPointer",
|
|
1098
|
+
get: function () {
|
|
1099
|
+
if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return false;
|
|
1100
|
+
return window.matchMedia('(pointer: coarse)').matches && window.matchMedia('(hover: none)').matches;
|
|
1101
|
+
}
|
|
982
1102
|
}, {
|
|
983
1103
|
key: "onMobile",
|
|
984
1104
|
get: function () {
|
|
1105
|
+
if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return false;
|
|
985
1106
|
return window.matchMedia(`(max-width: ${this.fullScreenThresholdValue}px)`).matches;
|
|
986
1107
|
}
|
|
987
1108
|
}], [{
|
|
@@ -33,6 +33,7 @@ var MESSAGE_TIMESTAMP_FORMAT_OPTIONS = {
|
|
|
33
33
|
hour: 'numeric',
|
|
34
34
|
minute: '2-digit'
|
|
35
35
|
};
|
|
36
|
+
var MOBILE_USER_AGENT_PATTERN = /Android|iPhone|iPad|iPod/i;
|
|
36
37
|
var SCROLL_ISOLATION_EVENT_OPTIONS = {
|
|
37
38
|
capture: true,
|
|
38
39
|
passive: true
|
|
@@ -51,13 +52,19 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
51
52
|
this.webChatChannel = new WebchatChannel(this.idValue, Hellotext.session, this.conversationIdValue);
|
|
52
53
|
this.files = [];
|
|
53
54
|
this.messageIds = new Set();
|
|
55
|
+
this.catchUpAfterMessageId = null;
|
|
56
|
+
this.fetchingCatchUpMessages = false;
|
|
54
57
|
this.onMessageReceived = this.onMessageReceived.bind(this);
|
|
55
58
|
this.onMessageReaction = this.onMessageReaction.bind(this);
|
|
56
59
|
this.onTypingStart = this.onTypingStart.bind(this);
|
|
60
|
+
this.captureCatchUpCursor = this.captureCatchUpCursor.bind(this);
|
|
61
|
+
this.catchUpMessages = this.catchUpMessages.bind(this);
|
|
57
62
|
this.onScroll = this.onScroll.bind(this);
|
|
58
63
|
this.onOutboundMessageSent = this.onOutboundMessageSent.bind(this);
|
|
59
64
|
this.closePopoverOnEscape = this.closePopoverOnEscape.bind(this);
|
|
60
65
|
this.broadcastChannel = new BroadcastChannel("hellotext--webchat--".concat(this.idValue));
|
|
66
|
+
this.webChatChannel.onDisconnect(this.captureCatchUpCursor);
|
|
67
|
+
this.webChatChannel.onReconnect(this.catchUpMessages);
|
|
61
68
|
_get(_getPrototypeOf(_default.prototype), "initialize", this).call(this);
|
|
62
69
|
}
|
|
63
70
|
}, {
|
|
@@ -260,7 +267,12 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
260
267
|
var div = document.createElement('div');
|
|
261
268
|
div.innerHTML = body;
|
|
262
269
|
var element = this.messageTemplateTarget.cloneNode(true);
|
|
270
|
+
element.classList.add('hellotext--webchat-message');
|
|
263
271
|
element.setAttribute('data-hellotext--webchat-target', 'message');
|
|
272
|
+
element.setAttribute('data-id', message.id);
|
|
273
|
+
if (createdAt) {
|
|
274
|
+
element.setAttribute('data-created-at', createdAt);
|
|
275
|
+
}
|
|
264
276
|
element.style.removeProperty('display');
|
|
265
277
|
element.querySelector('[data-body]').innerHTML = div.innerHTML;
|
|
266
278
|
if (message.state === 'received') {
|
|
@@ -335,7 +347,7 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
335
347
|
this.popoverTarget.classList.remove(...this.fadeOutClasses);
|
|
336
348
|
(_this$dismissTeaserFo = this.dismissTeaserForSession) === null || _this$dismissTeaserFo === void 0 ? void 0 : _this$dismissTeaserFo.call(this);
|
|
337
349
|
if (!this.onMobile) {
|
|
338
|
-
this.
|
|
350
|
+
this.focusComposeInput();
|
|
339
351
|
}
|
|
340
352
|
if (!this.scrolled) {
|
|
341
353
|
requestAnimationFrame(() => {
|
|
@@ -392,6 +404,7 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
392
404
|
key: "onMessageReceived",
|
|
393
405
|
value: function onMessageReceived(message) {
|
|
394
406
|
var _this$hideTeaser;
|
|
407
|
+
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
395
408
|
var {
|
|
396
409
|
id,
|
|
397
410
|
body,
|
|
@@ -402,15 +415,17 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
402
415
|
if (!this.claimMessageId(id)) return;
|
|
403
416
|
(_this$hideTeaser = this.hideTeaser) === null || _this$hideTeaser === void 0 ? void 0 : _this$hideTeaser.call(this);
|
|
404
417
|
if (message.carousel) {
|
|
405
|
-
return this.insertCarouselMessage(message);
|
|
418
|
+
return this.insertCarouselMessage(message, options);
|
|
406
419
|
}
|
|
407
420
|
var div = document.createElement('div');
|
|
408
421
|
div.innerHTML = body;
|
|
409
422
|
var element = this.messageTemplateTarget.cloneNode(true);
|
|
423
|
+
element.classList.add('hellotext--webchat-message');
|
|
410
424
|
element.style.display = 'flex';
|
|
411
425
|
element.querySelector('[data-body]').innerHTML = div.innerHTML;
|
|
412
426
|
element.setAttribute('data-id', id);
|
|
413
427
|
element.setAttribute('data-hellotext--webchat-target', 'message');
|
|
428
|
+
this.setMessageCreatedAt(element, createdAt);
|
|
414
429
|
this.localizeMessageTimestamp(element.querySelector('[data-message-timestamp]'), createdAt);
|
|
415
430
|
if (attachments) {
|
|
416
431
|
attachments.forEach(attachmentUrl => {
|
|
@@ -422,13 +437,15 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
422
437
|
});
|
|
423
438
|
}
|
|
424
439
|
this.clearTypingIndicator();
|
|
425
|
-
this.
|
|
440
|
+
this.insertMessageElement(element);
|
|
426
441
|
Hellotext.eventEmitter.dispatch('webchat:message:received', _objectSpread(_objectSpread({}, message), {}, {
|
|
427
442
|
body: element.querySelector('[data-body]').innerText
|
|
428
443
|
}));
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
444
|
+
if (options.scroll !== false) {
|
|
445
|
+
element.scrollIntoView({
|
|
446
|
+
behavior: 'smooth'
|
|
447
|
+
});
|
|
448
|
+
}
|
|
432
449
|
this.updateMessageTeaser(teaser);
|
|
433
450
|
if (this.openValue) {
|
|
434
451
|
this.messagesAPI.markAsSeen(id);
|
|
@@ -448,6 +465,76 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
448
465
|
this.messageIds.add(id);
|
|
449
466
|
return !messageTargets.some(element => element.dataset.id === id);
|
|
450
467
|
}
|
|
468
|
+
}, {
|
|
469
|
+
key: "captureCatchUpCursor",
|
|
470
|
+
value: function captureCatchUpCursor() {
|
|
471
|
+
this.catchUpAfterMessageId = this.lastRenderedMessageId;
|
|
472
|
+
}
|
|
473
|
+
}, {
|
|
474
|
+
key: "catchUpMessages",
|
|
475
|
+
value: function () {
|
|
476
|
+
var _catchUpMessages = _asyncToGenerator(function* () {
|
|
477
|
+
var afterId = this.catchUpAfterMessageId;
|
|
478
|
+
if (!afterId || this.fetchingCatchUpMessages) return;
|
|
479
|
+
this.fetchingCatchUpMessages = true;
|
|
480
|
+
try {
|
|
481
|
+
var response = yield this.messagesAPI.catchUp(afterId);
|
|
482
|
+
var {
|
|
483
|
+
messages = []
|
|
484
|
+
} = yield response.json();
|
|
485
|
+
messages.forEach(message => this.onMessageReceived(message, {
|
|
486
|
+
scroll: false
|
|
487
|
+
}));
|
|
488
|
+
this.catchUpAfterMessageId = this.lastRenderedMessageId;
|
|
489
|
+
} finally {
|
|
490
|
+
this.fetchingCatchUpMessages = false;
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
function catchUpMessages() {
|
|
494
|
+
return _catchUpMessages.apply(this, arguments);
|
|
495
|
+
}
|
|
496
|
+
return catchUpMessages;
|
|
497
|
+
}()
|
|
498
|
+
}, {
|
|
499
|
+
key: "lastRenderedMessageId",
|
|
500
|
+
get: function get() {
|
|
501
|
+
var _messages;
|
|
502
|
+
var messages = this.persistedMessageElements;
|
|
503
|
+
return ((_messages = messages[messages.length - 1]) === null || _messages === void 0 ? void 0 : _messages.dataset.id) || null;
|
|
504
|
+
}
|
|
505
|
+
}, {
|
|
506
|
+
key: "persistedMessageElements",
|
|
507
|
+
get: function get() {
|
|
508
|
+
return Array.from(this.messagesContainerTarget.querySelectorAll('.hellotext--webchat-message[data-id]'));
|
|
509
|
+
}
|
|
510
|
+
}, {
|
|
511
|
+
key: "setMessageCreatedAt",
|
|
512
|
+
value: function setMessageCreatedAt(element, createdAt) {
|
|
513
|
+
if (createdAt) {
|
|
514
|
+
element.setAttribute('data-created-at', createdAt);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}, {
|
|
518
|
+
key: "insertMessageElement",
|
|
519
|
+
value: function insertMessageElement(element) {
|
|
520
|
+
var nextElement = this.nextMessageElementFor(element);
|
|
521
|
+
if (nextElement) {
|
|
522
|
+
this.messagesContainerTarget.insertBefore(element, nextElement);
|
|
523
|
+
} else {
|
|
524
|
+
this.messagesContainerTarget.appendChild(element);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}, {
|
|
528
|
+
key: "nextMessageElementFor",
|
|
529
|
+
value: function nextMessageElementFor(element) {
|
|
530
|
+
var createdAt = Date.parse(element.dataset.createdAt);
|
|
531
|
+
if (Number.isNaN(createdAt)) return null;
|
|
532
|
+
return this.persistedMessageElements.find(messageElement => {
|
|
533
|
+
if (messageElement === element) return false;
|
|
534
|
+
var messageCreatedAt = Date.parse(messageElement.dataset.createdAt);
|
|
535
|
+
return !Number.isNaN(messageCreatedAt) && messageCreatedAt > createdAt;
|
|
536
|
+
});
|
|
537
|
+
}
|
|
451
538
|
}, {
|
|
452
539
|
key: "updateMessageTeaser",
|
|
453
540
|
value: function updateMessageTeaser(teaser) {
|
|
@@ -464,16 +551,22 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
464
551
|
key: "insertCarouselMessage",
|
|
465
552
|
value: function insertCarouselMessage(message) {
|
|
466
553
|
var _element$querySelecto;
|
|
554
|
+
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
467
555
|
var html = message.html;
|
|
556
|
+
var createdAt = message.created_at || message.createdAt;
|
|
468
557
|
var element = new DOMParser().parseFromString(html, 'text/html').body.firstElementChild;
|
|
558
|
+
element.classList.add('hellotext--webchat-message');
|
|
469
559
|
element.setAttribute('data-id', message.id);
|
|
470
560
|
element.setAttribute('data-hellotext--webchat-target', 'message');
|
|
561
|
+
this.setMessageCreatedAt(element, createdAt);
|
|
471
562
|
this.localizeMessageTimestamps(element);
|
|
472
563
|
this.clearTypingIndicator();
|
|
473
|
-
this.
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
564
|
+
this.insertMessageElement(element);
|
|
565
|
+
if (options.scroll !== false) {
|
|
566
|
+
element.scrollIntoView({
|
|
567
|
+
behavior: 'smooth'
|
|
568
|
+
});
|
|
569
|
+
}
|
|
477
570
|
Hellotext.eventEmitter.dispatch('webchat:message:received', _objectSpread(_objectSpread({}, message), {}, {
|
|
478
571
|
body: ((_element$querySelecto = element.querySelector('[data-body]')) === null || _element$querySelecto === void 0 ? void 0 : _element$querySelecto.innerText) || ''
|
|
479
572
|
}));
|
|
@@ -705,7 +798,7 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
705
798
|
this.attachmentContainerTarget.innerHTML = '';
|
|
706
799
|
this.attachmentContainerTarget.style.display = 'none';
|
|
707
800
|
this.errorMessageContainerTarget.style.display = 'none';
|
|
708
|
-
this.
|
|
801
|
+
this.focusComposeInput();
|
|
709
802
|
|
|
710
803
|
// Set up optimistic typing indicator BEFORE making the API call
|
|
711
804
|
// This prevents race conditions with server responses
|
|
@@ -763,12 +856,10 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
763
856
|
} = event;
|
|
764
857
|
var ignoredSelector = ['button', 'a', 'input', 'textarea', 'select', 'label', '[role="button"]', 'em-emoji-picker', '[data-hellotext--webchat--emoji-target~="popover"]', '[data-controller~="hellotext--webchat--emoji"]'].join(', ');
|
|
765
858
|
if (!this.hasInputTarget || target.closest(ignoredSelector)) return;
|
|
859
|
+
if (!this.focusComposeInput({
|
|
860
|
+
moveCursorToEnd: true
|
|
861
|
+
})) return;
|
|
766
862
|
event.preventDefault();
|
|
767
|
-
this.inputTarget.focus();
|
|
768
|
-
if (typeof this.inputTarget.selectionStart === 'number') {
|
|
769
|
-
var position = this.inputTarget.value.length;
|
|
770
|
-
this.inputTarget.setSelectionRange(position, position);
|
|
771
|
-
}
|
|
772
863
|
}
|
|
773
864
|
}, {
|
|
774
865
|
key: "closePopoverFromHeader",
|
|
@@ -931,7 +1022,7 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
931
1022
|
this.files = [...this.files, ...newFiles];
|
|
932
1023
|
this.errorMessageContainerTarget.innerText = '';
|
|
933
1024
|
newFiles.forEach(file => this.createAttachmentElement(file));
|
|
934
|
-
this.
|
|
1025
|
+
this.focusComposeInput();
|
|
935
1026
|
}
|
|
936
1027
|
}, {
|
|
937
1028
|
key: "createAttachmentElement",
|
|
@@ -967,7 +1058,7 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
967
1058
|
this.files = this.files.filter(file => file.name !== attachment.dataset.name);
|
|
968
1059
|
this.attachmentInputTarget.value = '';
|
|
969
1060
|
attachment.remove();
|
|
970
|
-
this.
|
|
1061
|
+
this.focusComposeInput();
|
|
971
1062
|
}
|
|
972
1063
|
}, {
|
|
973
1064
|
key: "attachmentTargetDisconnected",
|
|
@@ -997,7 +1088,23 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
997
1088
|
var end = this.inputTarget.selectionEnd;
|
|
998
1089
|
this.inputTarget.value = value.slice(0, start) + emoji + value.slice(end);
|
|
999
1090
|
this.inputTarget.selectionStart = this.inputTarget.selectionEnd = start + emoji.length;
|
|
1091
|
+
this.focusComposeInput();
|
|
1092
|
+
}
|
|
1093
|
+
}, {
|
|
1094
|
+
key: "focusComposeInput",
|
|
1095
|
+
value: function focusComposeInput() {
|
|
1096
|
+
var {
|
|
1097
|
+
moveCursorToEnd = false
|
|
1098
|
+
} = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
1099
|
+
if (!this.shouldAutofocusCompose) return false;
|
|
1100
|
+
if (this.hasInputTarget === false) return false;
|
|
1101
|
+
if (this.hasInputTarget === undefined && !this.inputTarget) return false;
|
|
1000
1102
|
this.inputTarget.focus();
|
|
1103
|
+
if (moveCursorToEnd && typeof this.inputTarget.selectionStart === 'number') {
|
|
1104
|
+
var position = this.inputTarget.value.length;
|
|
1105
|
+
this.inputTarget.setSelectionRange(position, position);
|
|
1106
|
+
}
|
|
1107
|
+
return true;
|
|
1001
1108
|
}
|
|
1002
1109
|
}, {
|
|
1003
1110
|
key: "byteToMegabyte",
|
|
@@ -1016,9 +1123,32 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
1016
1123
|
get: function get() {
|
|
1017
1124
|
return localStorage.getItem("hellotext--webchat--".concat(this.idValue)) === 'opened' && !this.onMobile;
|
|
1018
1125
|
}
|
|
1126
|
+
}, {
|
|
1127
|
+
key: "shouldAutofocusCompose",
|
|
1128
|
+
get: function get() {
|
|
1129
|
+
return !this.usesVirtualKeyboard;
|
|
1130
|
+
}
|
|
1131
|
+
}, {
|
|
1132
|
+
key: "usesVirtualKeyboard",
|
|
1133
|
+
get: function get() {
|
|
1134
|
+
var _navigator$userAgentD;
|
|
1135
|
+
if (typeof navigator === 'undefined') return false;
|
|
1136
|
+
var userAgent = navigator.userAgent || '';
|
|
1137
|
+
var isIPadOS = navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1;
|
|
1138
|
+
var isMobileUserAgent = MOBILE_USER_AGENT_PATTERN.test(userAgent);
|
|
1139
|
+
var isUserAgentDataMobile = ((_navigator$userAgentD = navigator.userAgentData) === null || _navigator$userAgentD === void 0 ? void 0 : _navigator$userAgentD.mobile) === true;
|
|
1140
|
+
return isMobileUserAgent || isIPadOS || isUserAgentDataMobile || this.hasTouchOnlyPointer;
|
|
1141
|
+
}
|
|
1142
|
+
}, {
|
|
1143
|
+
key: "hasTouchOnlyPointer",
|
|
1144
|
+
get: function get() {
|
|
1145
|
+
if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return false;
|
|
1146
|
+
return window.matchMedia('(pointer: coarse)').matches && window.matchMedia('(hover: none)').matches;
|
|
1147
|
+
}
|
|
1019
1148
|
}, {
|
|
1020
1149
|
key: "onMobile",
|
|
1021
1150
|
get: function get() {
|
|
1151
|
+
if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return false;
|
|
1022
1152
|
return window.matchMedia("(max-width: ".concat(this.fullScreenThresholdValue, "px)")).matches;
|
|
1023
1153
|
}
|
|
1024
1154
|
}], [{
|
package/package.json
CHANGED