quikchat 1.1.17 → 1.2.4
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 +167 -276
- package/dist/build-manifest.json +157 -0
- package/dist/quikchat-md-full.cjs.js +2742 -0
- package/dist/quikchat-md-full.cjs.js.map +1 -0
- package/dist/quikchat-md-full.cjs.min.js +10 -0
- package/dist/quikchat-md-full.cjs.min.js.map +1 -0
- package/dist/quikchat-md-full.esm.js +2740 -0
- package/dist/quikchat-md-full.esm.js.map +1 -0
- package/dist/quikchat-md-full.esm.min.js +10 -0
- package/dist/quikchat-md-full.esm.min.js.map +1 -0
- package/dist/quikchat-md-full.umd.js +2748 -0
- package/dist/quikchat-md-full.umd.js.map +1 -0
- package/dist/quikchat-md-full.umd.min.js +10 -0
- package/dist/quikchat-md-full.umd.min.js.map +1 -0
- package/dist/quikchat-md.cjs.js +1641 -0
- package/dist/quikchat-md.cjs.js.map +1 -0
- package/dist/quikchat-md.cjs.min.js +8 -0
- package/dist/quikchat-md.cjs.min.js.map +1 -0
- package/dist/quikchat-md.esm.js +1639 -0
- package/dist/quikchat-md.esm.js.map +1 -0
- package/dist/quikchat-md.esm.min.js +8 -0
- package/dist/quikchat-md.esm.min.js.map +1 -0
- package/dist/quikchat-md.umd.js +1647 -0
- package/dist/quikchat-md.umd.js.map +1 -0
- package/dist/quikchat-md.umd.min.js +8 -0
- package/dist/quikchat-md.umd.min.js.map +1 -0
- package/dist/quikchat.cjs.js +454 -1729
- package/dist/quikchat.cjs.js.map +1 -1
- package/dist/quikchat.cjs.min.js +1 -1
- package/dist/quikchat.cjs.min.js.map +1 -1
- package/dist/quikchat.css +753 -226
- package/dist/quikchat.esm.js +454 -1729
- package/dist/quikchat.esm.js.map +1 -1
- package/dist/quikchat.esm.min.js +1 -1
- package/dist/quikchat.esm.min.js.map +1 -1
- package/dist/quikchat.min.css +1 -1
- package/dist/quikchat.react.js +63 -0
- package/dist/quikchat.umd.js +454 -1729
- package/dist/quikchat.umd.js.map +1 -1
- package/dist/quikchat.umd.min.js +1 -1
- package/dist/quikchat.umd.min.js.map +1 -1
- package/package.json +59 -39
- package/dist/quikchat.d.ts +0 -194
package/dist/quikchat.cjs.js
CHANGED
|
@@ -5,37 +5,76 @@ function _arrayLikeToArray(r, a) {
|
|
|
5
5
|
for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
|
|
6
6
|
return n;
|
|
7
7
|
}
|
|
8
|
-
function _arrayWithoutHoles(r) {
|
|
9
|
-
if (Array.isArray(r)) return _arrayLikeToArray(r);
|
|
10
|
-
}
|
|
11
8
|
function _classCallCheck(a, n) {
|
|
12
9
|
if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function");
|
|
13
10
|
}
|
|
14
11
|
function _defineProperties(e, r) {
|
|
15
12
|
for (var t = 0; t < r.length; t++) {
|
|
16
13
|
var o = r[t];
|
|
17
|
-
o.enumerable = o.enumerable ||
|
|
14
|
+
o.enumerable = o.enumerable || false, o.configurable = true, "value" in o && (o.writable = true), Object.defineProperty(e, _toPropertyKey(o.key), o);
|
|
18
15
|
}
|
|
19
16
|
}
|
|
20
17
|
function _createClass(e, r, t) {
|
|
21
18
|
return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", {
|
|
22
|
-
writable:
|
|
19
|
+
writable: false
|
|
23
20
|
}), e;
|
|
24
21
|
}
|
|
22
|
+
function _createForOfIteratorHelper(r, e) {
|
|
23
|
+
var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
|
|
24
|
+
if (!t) {
|
|
25
|
+
if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e) {
|
|
26
|
+
t && (r = t);
|
|
27
|
+
var n = 0,
|
|
28
|
+
F = function () {};
|
|
29
|
+
return {
|
|
30
|
+
s: F,
|
|
31
|
+
n: function () {
|
|
32
|
+
return n >= r.length ? {
|
|
33
|
+
done: true
|
|
34
|
+
} : {
|
|
35
|
+
done: false,
|
|
36
|
+
value: r[n++]
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
e: function (r) {
|
|
40
|
+
throw r;
|
|
41
|
+
},
|
|
42
|
+
f: F
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
46
|
+
}
|
|
47
|
+
var o,
|
|
48
|
+
a = true,
|
|
49
|
+
u = false;
|
|
50
|
+
return {
|
|
51
|
+
s: function () {
|
|
52
|
+
t = t.call(r);
|
|
53
|
+
},
|
|
54
|
+
n: function () {
|
|
55
|
+
var r = t.next();
|
|
56
|
+
return a = r.done, r;
|
|
57
|
+
},
|
|
58
|
+
e: function (r) {
|
|
59
|
+
u = true, o = r;
|
|
60
|
+
},
|
|
61
|
+
f: function () {
|
|
62
|
+
try {
|
|
63
|
+
a || null == t.return || t.return();
|
|
64
|
+
} finally {
|
|
65
|
+
if (u) throw o;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
}
|
|
25
70
|
function _defineProperty(e, r, t) {
|
|
26
71
|
return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
27
72
|
value: t,
|
|
28
|
-
enumerable:
|
|
29
|
-
configurable:
|
|
30
|
-
writable:
|
|
73
|
+
enumerable: true,
|
|
74
|
+
configurable: true,
|
|
75
|
+
writable: true
|
|
31
76
|
}) : e[r] = t, e;
|
|
32
77
|
}
|
|
33
|
-
function _iterableToArray(r) {
|
|
34
|
-
if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r);
|
|
35
|
-
}
|
|
36
|
-
function _nonIterableSpread() {
|
|
37
|
-
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
38
|
-
}
|
|
39
78
|
function ownKeys(e, r) {
|
|
40
79
|
var t = Object.keys(e);
|
|
41
80
|
if (Object.getOwnPropertySymbols) {
|
|
@@ -49,7 +88,7 @@ function ownKeys(e, r) {
|
|
|
49
88
|
function _objectSpread2(e) {
|
|
50
89
|
for (var r = 1; r < arguments.length; r++) {
|
|
51
90
|
var t = null != arguments[r] ? arguments[r] : {};
|
|
52
|
-
r % 2 ? ownKeys(Object(t),
|
|
91
|
+
r % 2 ? ownKeys(Object(t), true).forEach(function (r) {
|
|
53
92
|
_defineProperty(e, r, t[r]);
|
|
54
93
|
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
|
|
55
94
|
Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
|
|
@@ -57,18 +96,15 @@ function _objectSpread2(e) {
|
|
|
57
96
|
}
|
|
58
97
|
return e;
|
|
59
98
|
}
|
|
60
|
-
function _toConsumableArray(r) {
|
|
61
|
-
return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread();
|
|
62
|
-
}
|
|
63
99
|
function _toPrimitive(t, r) {
|
|
64
100
|
if ("object" != typeof t || !t) return t;
|
|
65
101
|
var e = t[Symbol.toPrimitive];
|
|
66
102
|
if (void 0 !== e) {
|
|
67
|
-
var i = e.call(t, r
|
|
103
|
+
var i = e.call(t, r);
|
|
68
104
|
if ("object" != typeof i) return i;
|
|
69
105
|
throw new TypeError("@@toPrimitive must return a primitive value.");
|
|
70
106
|
}
|
|
71
|
-
return (
|
|
107
|
+
return (String )(t);
|
|
72
108
|
}
|
|
73
109
|
function _toPropertyKey(t) {
|
|
74
110
|
var i = _toPrimitive(t, "string");
|
|
@@ -82,378 +118,11 @@ function _unsupportedIterableToArray(r, a) {
|
|
|
82
118
|
}
|
|
83
119
|
}
|
|
84
120
|
|
|
85
|
-
// Auto-generated version file - DO NOT EDIT MANUALLY
|
|
86
|
-
// This file is automatically updated by tools/updateVersion.js
|
|
87
|
-
|
|
88
|
-
var quikchatVersion = {
|
|
89
|
-
version: "1.1.17",
|
|
90
|
-
license: "BSD-2",
|
|
91
|
-
url: "https://github/deftio/quikchat",
|
|
92
|
-
fun: true
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Simplified virtual scrolling implementation for QuikChat
|
|
97
|
-
* @private
|
|
98
|
-
*/
|
|
99
|
-
var SimpleVirtualScroller = /*#__PURE__*/function () {
|
|
100
|
-
function SimpleVirtualScroller(container) {
|
|
101
|
-
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
102
|
-
_classCallCheck(this, SimpleVirtualScroller);
|
|
103
|
-
this.container = container;
|
|
104
|
-
this.items = [];
|
|
105
|
-
this.itemHeight = options.itemHeight || 80; // Default/estimate height
|
|
106
|
-
this.buffer = options.buffer || 5;
|
|
107
|
-
this.visibleRange = {
|
|
108
|
-
start: 0,
|
|
109
|
-
end: 0
|
|
110
|
-
};
|
|
111
|
-
this.renderedElements = new Map();
|
|
112
|
-
this.itemHeights = new Map(); // Cache actual heights
|
|
113
|
-
this.itemPositions = new Map(); // Cache positions
|
|
114
|
-
this.totalHeight = 0;
|
|
115
|
-
this.onRenderItem = options.onRenderItem || function () {};
|
|
116
|
-
this.sanitizer = options.sanitizer || null; // Content sanitizer
|
|
117
|
-
|
|
118
|
-
this._initStructure();
|
|
119
|
-
this._attachScrollListener();
|
|
120
|
-
}
|
|
121
|
-
return _createClass(SimpleVirtualScroller, [{
|
|
122
|
-
key: "_initStructure",
|
|
123
|
-
value: function _initStructure() {
|
|
124
|
-
var _this = this;
|
|
125
|
-
var existingClasses = this.container.className;
|
|
126
|
-
this.container.innerHTML = '';
|
|
127
|
-
this.container.className = existingClasses;
|
|
128
|
-
this.container.style.position = 'relative';
|
|
129
|
-
this.container.style.overflow = 'auto';
|
|
130
|
-
|
|
131
|
-
// Ensure container has height
|
|
132
|
-
if (this.container.offsetHeight === 0) {
|
|
133
|
-
// Try to get height from computed style or parent
|
|
134
|
-
var computedHeight = window.getComputedStyle(this.container).height;
|
|
135
|
-
if (computedHeight === '0px' || computedHeight === 'auto') {
|
|
136
|
-
// If still no height, use a reasonable default
|
|
137
|
-
this.container.style.height = '400px';
|
|
138
|
-
console.warn('QuikChat Virtual Scrolling: Container has no height, setting to 400px');
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
this.spacer = document.createElement('div');
|
|
142
|
-
this.spacer.style.cssText = 'position: absolute; top: 0; left: 0; width: 1px; pointer-events: none; z-index: -1;';
|
|
143
|
-
this.content = document.createElement('div');
|
|
144
|
-
this.content.style.cssText = 'position: relative; width: 100%;';
|
|
145
|
-
this.container.appendChild(this.spacer);
|
|
146
|
-
this.container.appendChild(this.content);
|
|
147
|
-
|
|
148
|
-
// Initial render after structure is set up
|
|
149
|
-
setTimeout(function () {
|
|
150
|
-
_this._updateVisibleRange();
|
|
151
|
-
_this._renderVisibleItems();
|
|
152
|
-
}, 0);
|
|
153
|
-
}
|
|
154
|
-
}, {
|
|
155
|
-
key: "_attachScrollListener",
|
|
156
|
-
value: function _attachScrollListener() {
|
|
157
|
-
var _this2 = this;
|
|
158
|
-
var ticking = false;
|
|
159
|
-
this.container.addEventListener('scroll', function () {
|
|
160
|
-
if (!ticking) {
|
|
161
|
-
requestAnimationFrame(function () {
|
|
162
|
-
_this2._updateVisibleRange();
|
|
163
|
-
_this2._renderVisibleItems();
|
|
164
|
-
ticking = false;
|
|
165
|
-
});
|
|
166
|
-
ticking = true;
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
}, {
|
|
171
|
-
key: "_getItemHeight",
|
|
172
|
-
value: function _getItemHeight(index) {
|
|
173
|
-
// Return cached height or estimate
|
|
174
|
-
return this.itemHeights.get(index) || this.itemHeight;
|
|
175
|
-
}
|
|
176
|
-
}, {
|
|
177
|
-
key: "_getItemPosition",
|
|
178
|
-
value: function _getItemPosition(index) {
|
|
179
|
-
// Return cached position or calculate
|
|
180
|
-
if (this.itemPositions.has(index)) {
|
|
181
|
-
return this.itemPositions.get(index);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Calculate position based on previous items
|
|
185
|
-
var position = 0;
|
|
186
|
-
for (var i = 0; i < index; i++) {
|
|
187
|
-
position += this._getItemHeight(i);
|
|
188
|
-
}
|
|
189
|
-
this.itemPositions.set(index, position);
|
|
190
|
-
return position;
|
|
191
|
-
}
|
|
192
|
-
}, {
|
|
193
|
-
key: "_recalculatePositions",
|
|
194
|
-
value: function _recalculatePositions(fromIndex) {
|
|
195
|
-
// Recalculate positions from a specific index onwards
|
|
196
|
-
var position = fromIndex > 0 ? this._getItemPosition(fromIndex) : 0;
|
|
197
|
-
for (var i = fromIndex; i < this.items.length; i++) {
|
|
198
|
-
this.itemPositions.set(i, position);
|
|
199
|
-
position += this._getItemHeight(i);
|
|
200
|
-
|
|
201
|
-
// Update position of rendered elements
|
|
202
|
-
var element = this.renderedElements.get(i);
|
|
203
|
-
if (element) {
|
|
204
|
-
element.style.top = "".concat(this.itemPositions.get(i), "px");
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// Update total height
|
|
209
|
-
this.totalHeight = position;
|
|
210
|
-
this.spacer.style.height = "".concat(this.totalHeight, "px");
|
|
211
|
-
}
|
|
212
|
-
}, {
|
|
213
|
-
key: "_updateVisibleRange",
|
|
214
|
-
value: function _updateVisibleRange() {
|
|
215
|
-
var scrollTop = this.container.scrollTop;
|
|
216
|
-
var viewportHeight = this.container.clientHeight;
|
|
217
|
-
|
|
218
|
-
// If container has no height, don't render anything (avoid infinite loop)
|
|
219
|
-
if (viewportHeight === 0) {
|
|
220
|
-
this.visibleRange = {
|
|
221
|
-
start: 0,
|
|
222
|
-
end: 0
|
|
223
|
-
};
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// Find first visible item based on positions
|
|
228
|
-
var startIndex = 0;
|
|
229
|
-
var endIndex = this.items.length;
|
|
230
|
-
|
|
231
|
-
// Use cached positions when available
|
|
232
|
-
if (this.itemPositions.size > 0) {
|
|
233
|
-
// Find start index
|
|
234
|
-
for (var i = 0; i < this.items.length; i++) {
|
|
235
|
-
var pos = this._getItemPosition(i);
|
|
236
|
-
if (pos + this._getItemHeight(i) > scrollTop) {
|
|
237
|
-
startIndex = Math.max(0, i - this.buffer);
|
|
238
|
-
break;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// Find end index
|
|
243
|
-
for (var _i = startIndex; _i < this.items.length; _i++) {
|
|
244
|
-
var _pos = this._getItemPosition(_i);
|
|
245
|
-
if (_pos > scrollTop + viewportHeight) {
|
|
246
|
-
endIndex = Math.min(this.items.length, _i + this.buffer);
|
|
247
|
-
break;
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
} else {
|
|
251
|
-
// Fallback to estimate if no positions cached yet
|
|
252
|
-
startIndex = Math.max(0, Math.floor(scrollTop / this.itemHeight) - this.buffer);
|
|
253
|
-
endIndex = Math.min(this.items.length, Math.ceil((scrollTop + viewportHeight) / this.itemHeight) + this.buffer);
|
|
254
|
-
}
|
|
255
|
-
this.visibleRange = {
|
|
256
|
-
start: startIndex,
|
|
257
|
-
end: endIndex
|
|
258
|
-
};
|
|
259
|
-
}
|
|
260
|
-
}, {
|
|
261
|
-
key: "_renderVisibleItems",
|
|
262
|
-
value: function _renderVisibleItems() {
|
|
263
|
-
var _this3 = this;
|
|
264
|
-
var _this$visibleRange = this.visibleRange,
|
|
265
|
-
start = _this$visibleRange.start,
|
|
266
|
-
end = _this$visibleRange.end;
|
|
267
|
-
|
|
268
|
-
// Remove elements outside range
|
|
269
|
-
this.renderedElements.forEach(function (element, index) {
|
|
270
|
-
if (index < start || index >= end) {
|
|
271
|
-
element.remove();
|
|
272
|
-
_this3.renderedElements["delete"](index);
|
|
273
|
-
// Don't clear height cache - we might need it again
|
|
274
|
-
}
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
// Add new visible elements
|
|
278
|
-
var _loop = function _loop(i) {
|
|
279
|
-
var item = _this3.items[i];
|
|
280
|
-
if (!item || _this3.renderedElements.has(i)) return 1; // continue
|
|
281
|
-
var element = _this3._createItemElement(item, i);
|
|
282
|
-
element.style.position = 'absolute';
|
|
283
|
-
element.style.top = "".concat(_this3._getItemPosition(i), "px");
|
|
284
|
-
element.style.left = '0';
|
|
285
|
-
element.style.right = '0';
|
|
286
|
-
_this3.renderedElements.set(i, element);
|
|
287
|
-
_this3.content.appendChild(element);
|
|
288
|
-
|
|
289
|
-
// Measure actual height after rendering
|
|
290
|
-
requestAnimationFrame(function () {
|
|
291
|
-
if (_this3.renderedElements.has(i)) {
|
|
292
|
-
var actualHeight = element.offsetHeight;
|
|
293
|
-
if (actualHeight && actualHeight !== _this3._getItemHeight(i)) {
|
|
294
|
-
_this3.itemHeights.set(i, actualHeight);
|
|
295
|
-
_this3._recalculatePositions(i);
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
});
|
|
299
|
-
};
|
|
300
|
-
for (var i = start; i < end; i++) {
|
|
301
|
-
if (_loop(i)) continue;
|
|
302
|
-
}
|
|
303
|
-
this.onRenderItem(this.content);
|
|
304
|
-
}
|
|
305
|
-
}, {
|
|
306
|
-
key: "_createItemElement",
|
|
307
|
-
value: function _createItemElement(item, index) {
|
|
308
|
-
var messageDiv = document.createElement('div');
|
|
309
|
-
messageDiv.className = "quikchat-message quikchat-message-".concat(item.align || 'left', " quikchat-msgid-").concat(String(item.msgid).padStart(10, '0'));
|
|
310
|
-
messageDiv.setAttribute('data-index', index);
|
|
311
|
-
messageDiv.setAttribute('data-msgid', item.msgid);
|
|
312
|
-
messageDiv.setAttribute('role', 'article');
|
|
313
|
-
messageDiv.setAttribute('aria-label', "Message from ".concat(item.userString || 'user'));
|
|
314
|
-
if (item.tags && item.tags.length > 0) {
|
|
315
|
-
item.tags.forEach(function (tag) {
|
|
316
|
-
return messageDiv.classList.add("quikchat-tag-".concat(tag));
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
|
-
var userDiv = document.createElement('div');
|
|
320
|
-
userDiv.className = 'quikchat-message-user';
|
|
321
|
-
userDiv.innerHTML = this.sanitizer ? this.sanitizer(item.userString || '') : item.userString || '';
|
|
322
|
-
userDiv.setAttribute('aria-label', 'User');
|
|
323
|
-
var contentDiv = document.createElement('div');
|
|
324
|
-
contentDiv.className = 'quikchat-message-content';
|
|
325
|
-
contentDiv.innerHTML = this.sanitizer ? this.sanitizer(item.content || '') : item.content || '';
|
|
326
|
-
contentDiv.setAttribute('aria-label', 'Message content');
|
|
327
|
-
messageDiv.appendChild(userDiv);
|
|
328
|
-
messageDiv.appendChild(contentDiv);
|
|
329
|
-
if (!item.visible) {
|
|
330
|
-
messageDiv.style.display = 'none';
|
|
331
|
-
}
|
|
332
|
-
return messageDiv;
|
|
333
|
-
}
|
|
334
|
-
}, {
|
|
335
|
-
key: "addItem",
|
|
336
|
-
value: function addItem(item) {
|
|
337
|
-
this.items.push(item);
|
|
338
|
-
var index = this.items.length - 1;
|
|
339
|
-
|
|
340
|
-
// Calculate position for new item
|
|
341
|
-
var position = index > 0 ? this._getItemPosition(index - 1) + this._getItemHeight(index - 1) : 0;
|
|
342
|
-
this.itemPositions.set(index, position);
|
|
343
|
-
|
|
344
|
-
// Update total height (using estimate for new item)
|
|
345
|
-
this.totalHeight = position + this.itemHeight;
|
|
346
|
-
this.spacer.style.height = "".concat(this.totalHeight, "px");
|
|
347
|
-
if (index >= this.visibleRange.start && index < this.visibleRange.end) {
|
|
348
|
-
this._renderVisibleItems();
|
|
349
|
-
}
|
|
350
|
-
if (item.scrollIntoView) {
|
|
351
|
-
this.container.scrollTop = this.container.scrollHeight;
|
|
352
|
-
}
|
|
353
|
-
return index;
|
|
354
|
-
}
|
|
355
|
-
}, {
|
|
356
|
-
key: "addItems",
|
|
357
|
-
value: function addItems(items) {
|
|
358
|
-
var _this$items;
|
|
359
|
-
// Batch add items for better performance
|
|
360
|
-
var startLength = this.items.length;
|
|
361
|
-
(_this$items = this.items).push.apply(_this$items, _toConsumableArray(items));
|
|
362
|
-
|
|
363
|
-
// Calculate positions for new items
|
|
364
|
-
var position = startLength > 0 ? this._getItemPosition(startLength - 1) + this._getItemHeight(startLength - 1) : 0;
|
|
365
|
-
for (var i = startLength; i < this.items.length; i++) {
|
|
366
|
-
this.itemPositions.set(i, position);
|
|
367
|
-
position += this.itemHeight; // Use estimate for new items
|
|
368
|
-
}
|
|
369
|
-
this.totalHeight = position;
|
|
370
|
-
this.spacer.style.height = "".concat(this.totalHeight, "px");
|
|
371
|
-
|
|
372
|
-
// Update visible range and render
|
|
373
|
-
this._updateVisibleRange();
|
|
374
|
-
this._renderVisibleItems();
|
|
375
|
-
|
|
376
|
-
// Handle scrollIntoView for last item if needed
|
|
377
|
-
if (items.length > 0 && items[items.length - 1].scrollIntoView) {
|
|
378
|
-
this.container.scrollTop = this.container.scrollHeight;
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
}, {
|
|
382
|
-
key: "clear",
|
|
383
|
-
value: function clear() {
|
|
384
|
-
this.items = [];
|
|
385
|
-
this.renderedElements.clear();
|
|
386
|
-
this.itemHeights.clear();
|
|
387
|
-
this.itemPositions.clear();
|
|
388
|
-
this.totalHeight = 0;
|
|
389
|
-
this.content.innerHTML = '';
|
|
390
|
-
this.spacer.style.height = '0px';
|
|
391
|
-
this.visibleRange = {
|
|
392
|
-
start: 0,
|
|
393
|
-
end: 0
|
|
394
|
-
};
|
|
395
|
-
|
|
396
|
-
// Force update after clear
|
|
397
|
-
this._updateVisibleRange();
|
|
398
|
-
this._renderVisibleItems();
|
|
399
|
-
}
|
|
400
|
-
}, {
|
|
401
|
-
key: "updateItem",
|
|
402
|
-
value: function updateItem(index, updates) {
|
|
403
|
-
if (index >= 0 && index < this.items.length) {
|
|
404
|
-
this.items[index] = _objectSpread2(_objectSpread2({}, this.items[index]), updates);
|
|
405
|
-
if (this.renderedElements.has(index)) {
|
|
406
|
-
this._renderVisibleItems();
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
}, {
|
|
411
|
-
key: "destroy",
|
|
412
|
-
value: function destroy() {
|
|
413
|
-
this.container.innerHTML = '';
|
|
414
|
-
this.items = [];
|
|
415
|
-
this.renderedElements.clear();
|
|
416
|
-
}
|
|
417
|
-
}]);
|
|
418
|
-
}();
|
|
419
|
-
/**
|
|
420
|
-
* QuikChat - A zero-dependency JavaScript chat widget for modern web applications
|
|
421
|
-
* @class quikchat
|
|
422
|
-
*/
|
|
423
121
|
var quikchat = /*#__PURE__*/function () {
|
|
424
122
|
/**
|
|
425
|
-
*
|
|
426
|
-
* @
|
|
427
|
-
* @param {
|
|
428
|
-
* @param {Function} [onSend] - Callback function triggered when user sends a message
|
|
429
|
-
* @param {Object} [options] - Configuration options
|
|
430
|
-
* @param {string} [options.theme='quikchat-theme-light'] - CSS theme class name
|
|
431
|
-
* @param {boolean} [options.trackHistory=true] - Whether to track message history
|
|
432
|
-
* @param {Object} [options.titleArea] - Title area configuration
|
|
433
|
-
* @param {string} [options.titleArea.title='Chat'] - Title text/HTML
|
|
434
|
-
* @param {boolean} [options.titleArea.show=false] - Whether to show title area initially
|
|
435
|
-
* @param {'left'|'center'|'right'} [options.titleArea.align='center'] - Title alignment
|
|
436
|
-
* @param {Object} [options.messagesArea] - Messages area configuration
|
|
437
|
-
* @param {boolean} [options.messagesArea.alternating=true] - Alternate message colors
|
|
438
|
-
* @param {Object} [options.inputArea] - Input area configuration
|
|
439
|
-
* @param {boolean} [options.inputArea.show=true] - Whether to show input area initially
|
|
440
|
-
* @param {boolean} [options.sendOnEnter=true] - Send message on Enter key
|
|
441
|
-
* @param {boolean} [options.sendOnShiftEnter=false] - Send message on Shift+Enter
|
|
442
|
-
* @param {string} [options.instanceClass=''] - Additional CSS class for the widget instance
|
|
443
|
-
* @example
|
|
444
|
-
* // Basic usage
|
|
445
|
-
* const chat = new quikchat('#chat-container', (instance, message) => {
|
|
446
|
-
* console.log('User sent:', message);
|
|
447
|
-
* });
|
|
448
|
-
*
|
|
449
|
-
* @example
|
|
450
|
-
* // With options
|
|
451
|
-
* const chat = new quikchat('#chat', handleMessage, {
|
|
452
|
-
* theme: 'quikchat-theme-dark',
|
|
453
|
-
* titleArea: { title: 'Support Chat', show: true },
|
|
454
|
-
* sendOnEnter: false,
|
|
455
|
-
* sendOnShiftEnter: true
|
|
456
|
-
* });
|
|
123
|
+
*
|
|
124
|
+
* @param string or DOM element parentElement
|
|
125
|
+
* @param {*} meta
|
|
457
126
|
*/
|
|
458
127
|
function quikchat(parentElement) {
|
|
459
128
|
var onSend = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {};
|
|
@@ -462,6 +131,7 @@ var quikchat = /*#__PURE__*/function () {
|
|
|
462
131
|
var defaultOpts = {
|
|
463
132
|
theme: 'quikchat-theme-light',
|
|
464
133
|
trackHistory: true,
|
|
134
|
+
showTimestamps: false,
|
|
465
135
|
titleArea: {
|
|
466
136
|
title: "Chat",
|
|
467
137
|
show: false,
|
|
@@ -469,55 +139,19 @@ var quikchat = /*#__PURE__*/function () {
|
|
|
469
139
|
},
|
|
470
140
|
messagesArea: {
|
|
471
141
|
alternating: true
|
|
472
|
-
}
|
|
473
|
-
inputArea: {
|
|
474
|
-
show: true
|
|
475
|
-
},
|
|
476
|
-
sendOnEnter: true,
|
|
477
|
-
sendOnShiftEnter: false,
|
|
478
|
-
instanceClass: '',
|
|
479
|
-
virtualScrolling: true,
|
|
480
|
-
// Default to true for better performance
|
|
481
|
-
virtualScrollingThreshold: 500,
|
|
482
|
-
// Lower threshold since it performs so well
|
|
483
|
-
// i18n support
|
|
484
|
-
lang: 'en',
|
|
485
|
-
dir: 'ltr',
|
|
486
|
-
// 'ltr' or 'rtl'
|
|
487
|
-
translations: {
|
|
488
|
-
'en': {
|
|
489
|
-
sendButton: 'Send',
|
|
490
|
-
inputPlaceholder: 'Type a message...',
|
|
491
|
-
titleDefault: 'Chat'
|
|
492
|
-
}
|
|
493
|
-
},
|
|
494
|
-
// Security: content sanitizer callback
|
|
495
|
-
sanitizer: null // null = no sanitization (backward compatible)
|
|
142
|
+
}
|
|
496
143
|
};
|
|
497
144
|
var meta = _objectSpread2(_objectSpread2({}, defaultOpts), options); // merge options with defaults
|
|
498
145
|
|
|
499
|
-
// Merge user translations with defaults
|
|
500
|
-
if (options.translations) {
|
|
501
|
-
meta.translations = _objectSpread2(_objectSpread2({}, defaultOpts.translations), options.translations);
|
|
502
|
-
}
|
|
503
146
|
if (typeof parentElement === 'string') {
|
|
504
147
|
parentElement = document.querySelector(parentElement);
|
|
505
148
|
}
|
|
506
|
-
//console.log(parentElement, meta);
|
|
507
149
|
this._parentElement = parentElement;
|
|
508
150
|
this._theme = meta.theme;
|
|
509
151
|
this._onSend = onSend ? onSend : function () {}; // call back function for onSend
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
this.lang = meta.lang;
|
|
513
|
-
this.dir = meta.dir;
|
|
514
|
-
this.translations = meta.translations;
|
|
515
|
-
this.currentTranslations = this.translations[this.lang] || this.translations['en'];
|
|
152
|
+
this._messageFormatter = meta.messageFormatter || null;
|
|
153
|
+
this._sanitize = meta.sanitize || false;
|
|
516
154
|
this._createWidget();
|
|
517
|
-
if (meta.instanceClass) {
|
|
518
|
-
this._chatWidget.classList.add(meta.instanceClass);
|
|
519
|
-
}
|
|
520
|
-
|
|
521
155
|
// title area
|
|
522
156
|
if (meta.titleArea) {
|
|
523
157
|
this.titleAreaSetContents(meta.titleArea.title, meta.titleArea.align);
|
|
@@ -531,176 +165,34 @@ var quikchat = /*#__PURE__*/function () {
|
|
|
531
165
|
if (meta.messagesArea) {
|
|
532
166
|
this.messagesAreaAlternateColors(meta.messagesArea.alternating);
|
|
533
167
|
}
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
168
|
+
// timestamps
|
|
169
|
+
if (meta.showTimestamps) {
|
|
170
|
+
this.messagesAreaShowTimestamps(true);
|
|
171
|
+
}
|
|
172
|
+
// direction (ltr/rtl)
|
|
173
|
+
if (meta.direction) {
|
|
174
|
+
this.setDirection(meta.direction);
|
|
538
175
|
}
|
|
539
176
|
// plumbing
|
|
540
177
|
this._attachEventListeners();
|
|
541
|
-
this.trackHistory = meta.trackHistory
|
|
178
|
+
this.trackHistory = meta.trackHistory !== false;
|
|
542
179
|
this._historyLimit = 10000000;
|
|
543
180
|
this._history = [];
|
|
544
|
-
this._activeTags = new Set();
|
|
545
|
-
|
|
546
|
-
// send on enter / shift enter
|
|
547
|
-
this.sendOnEnter = meta.sendOnEnter;
|
|
548
|
-
this.sendOnShiftEnter = meta.sendOnShiftEnter;
|
|
549
|
-
|
|
550
|
-
// Virtual scrolling setup
|
|
551
|
-
this.virtualScrollingEnabled = meta.virtualScrolling;
|
|
552
|
-
this.virtualScrollingThreshold = meta.virtualScrollingThreshold;
|
|
553
|
-
this.virtualScroller = null;
|
|
554
|
-
|
|
555
|
-
// Sanitizer setup
|
|
556
|
-
this._sanitizer = meta.sanitizer || null;
|
|
557
|
-
|
|
558
|
-
// Don't initialize virtual scrolling immediately - wait for threshold
|
|
559
|
-
// Virtual scrolling will be initialized when message count exceeds threshold
|
|
560
181
|
}
|
|
561
|
-
|
|
562
|
-
/**
|
|
563
|
-
* Initialize virtual scrolling
|
|
564
|
-
* @private
|
|
565
|
-
*/
|
|
566
182
|
return _createClass(quikchat, [{
|
|
567
|
-
key: "_initVirtualScrolling",
|
|
568
|
-
value: function _initVirtualScrolling() {
|
|
569
|
-
var _this4 = this;
|
|
570
|
-
if (this.virtualScrollingEnabled && this._messagesArea && !this.virtualScroller) {
|
|
571
|
-
// Check if we've hit the threshold (or about to with the next message)
|
|
572
|
-
if (this._history.length >= this.virtualScrollingThreshold - 1) {
|
|
573
|
-
this.virtualScroller = new SimpleVirtualScroller(this._messagesArea, {
|
|
574
|
-
itemHeight: 80,
|
|
575
|
-
buffer: 5,
|
|
576
|
-
sanitizer: this._sanitizer,
|
|
577
|
-
// Pass sanitizer to virtual scroller
|
|
578
|
-
onRenderItem: function onRenderItem(content) {
|
|
579
|
-
// Apply alternating colors if enabled
|
|
580
|
-
if (_this4._messagesArea.classList.contains('quikchat-messages-area-alt')) {
|
|
581
|
-
_this4._updateMessageStyles();
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
});
|
|
585
|
-
|
|
586
|
-
// Migrate existing messages to virtual scroller
|
|
587
|
-
this._migrateToVirtualScrolling();
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
/**
|
|
593
|
-
* Migrate existing messages to virtual scrolling
|
|
594
|
-
* @private
|
|
595
|
-
*/
|
|
596
|
-
}, {
|
|
597
|
-
key: "_migrateToVirtualScrolling",
|
|
598
|
-
value: function _migrateToVirtualScrolling() {
|
|
599
|
-
var _this5 = this;
|
|
600
|
-
if (!this.virtualScroller) return;
|
|
601
|
-
|
|
602
|
-
// Don't clear DOM here - virtual scroller will do it in _initStructure
|
|
603
|
-
|
|
604
|
-
// Add all messages to virtual scroller
|
|
605
|
-
var items = this._history.map(function (msg) {
|
|
606
|
-
return {
|
|
607
|
-
msgid: msg.msgid,
|
|
608
|
-
content: msg.content,
|
|
609
|
-
userString: msg.userString,
|
|
610
|
-
align: msg.align,
|
|
611
|
-
role: msg.role,
|
|
612
|
-
visible: msg.visible,
|
|
613
|
-
tags: msg.tags || [],
|
|
614
|
-
scrollIntoView: false
|
|
615
|
-
};
|
|
616
|
-
});
|
|
617
|
-
this.virtualScroller.addItems(items);
|
|
618
|
-
|
|
619
|
-
// Force a render in case container needs time to get dimensions
|
|
620
|
-
setTimeout(function () {
|
|
621
|
-
if (_this5.virtualScroller) {
|
|
622
|
-
_this5.virtualScroller._updateVisibleRange();
|
|
623
|
-
_this5.virtualScroller._renderVisibleItems();
|
|
624
|
-
}
|
|
625
|
-
}, 10);
|
|
626
|
-
}
|
|
627
|
-
}, {
|
|
628
183
|
key: "_createWidget",
|
|
629
184
|
value: function _createWidget() {
|
|
630
|
-
var
|
|
631
|
-
var inputPlaceholder = this.currentTranslations.inputPlaceholder || 'Type a message...';
|
|
632
|
-
var widgetHTML = "\n <div class=\"quikchat-base ".concat(this._theme, "\" dir=\"").concat(this.dir, "\" lang=\"").concat(this.lang, "\" role=\"region\" aria-label=\"Chat widget\">\n <div class=\"quikchat-title-area\" role=\"heading\" aria-level=\"2\">\n <span style=\"font-size: 1.5em; font-weight: 600;\">Title Area</span>\n </div>\n <div class=\"quikchat-messages-area\" role=\"log\" aria-live=\"polite\" aria-label=\"Chat messages\"></div>\n <div class=\"quikchat-input-area\" role=\"form\" aria-label=\"Message input\">\n <textarea class=\"quikchat-input-textbox\" \n placeholder=\"").concat(inputPlaceholder, "\"\n aria-label=\"Type your message\"\n autocomplete=\"off\"\n autocapitalize=\"sentences\"></textarea>\n <button class=\"quikchat-input-send-btn\" \n aria-label=\"Send message\"\n type=\"button\">").concat(sendButtonText, "</button>\n </div>\n </div>\n ");
|
|
185
|
+
var widgetHTML = "\n <div class=\"quikchat-base ".concat(this.theme, "\">\n <div class=\"quikchat-title-area\"></div>\n <div class=\"quikchat-messages-wrapper\"><div class=\"quikchat-messages-area\" role=\"log\" aria-live=\"polite\" aria-label=\"Chat messages\"></div><button class=\"quikchat-scroll-bottom\" aria-label=\"Scroll to bottom\"></button></div>\n <div class=\"quikchat-input-area\">\n <textarea class=\"quikchat-input-textbox\" rows=\"1\" aria-label=\"Type a message\"></textarea>\n <button class=\"quikchat-input-send-btn\">Send</button>\n </div>\n </div>\n ");
|
|
633
186
|
this._parentElement.innerHTML = widgetHTML;
|
|
634
187
|
this._chatWidget = this._parentElement.querySelector('.quikchat-base');
|
|
635
188
|
this._titleArea = this._chatWidget.querySelector('.quikchat-title-area');
|
|
189
|
+
this._messagesWrapper = this._chatWidget.querySelector('.quikchat-messages-wrapper');
|
|
636
190
|
this._messagesArea = this._chatWidget.querySelector('.quikchat-messages-area');
|
|
191
|
+
this._scrollBottomBtn = this._messagesWrapper.querySelector('.quikchat-scroll-bottom');
|
|
637
192
|
this._inputArea = this._chatWidget.querySelector('.quikchat-input-area');
|
|
638
193
|
this._textEntry = this._inputArea.querySelector('.quikchat-input-textbox');
|
|
639
194
|
this._sendButton = this._inputArea.querySelector('.quikchat-input-send-btn');
|
|
640
195
|
this.msgid = 0;
|
|
641
|
-
|
|
642
|
-
// Add mobile viewport handling
|
|
643
|
-
this._setupMobileSupport();
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
/**
|
|
647
|
-
* Setup mobile support - prevent zoom on input focus and handle virtual keyboard
|
|
648
|
-
* @private
|
|
649
|
-
*/
|
|
650
|
-
}, {
|
|
651
|
-
key: "_setupMobileSupport",
|
|
652
|
-
value: function _setupMobileSupport() {
|
|
653
|
-
var _this6 = this;
|
|
654
|
-
// Prevent zoom on input focus for mobile
|
|
655
|
-
var meta = document.querySelector('meta[name="viewport"]');
|
|
656
|
-
if (!meta) {
|
|
657
|
-
meta = document.createElement('meta');
|
|
658
|
-
meta.name = 'viewport';
|
|
659
|
-
document.head.appendChild(meta);
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
// Store original content
|
|
663
|
-
this._originalViewport = meta.content;
|
|
664
|
-
|
|
665
|
-
// Prevent zoom on focus
|
|
666
|
-
this._textEntry.addEventListener('focus', function () {
|
|
667
|
-
if (window.innerWidth <= 768) {
|
|
668
|
-
// Mobile device width
|
|
669
|
-
meta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0';
|
|
670
|
-
}
|
|
671
|
-
});
|
|
672
|
-
this._textEntry.addEventListener('blur', function () {
|
|
673
|
-
if (_this6._originalViewport) {
|
|
674
|
-
meta.content = _this6._originalViewport;
|
|
675
|
-
} else {
|
|
676
|
-
meta.content = 'width=device-width, initial-scale=1.0';
|
|
677
|
-
}
|
|
678
|
-
});
|
|
679
|
-
|
|
680
|
-
// Handle virtual keyboard resize
|
|
681
|
-
if ('visualViewport' in window) {
|
|
682
|
-
window.visualViewport.addEventListener('resize', function () {
|
|
683
|
-
_this6._handleVirtualKeyboard();
|
|
684
|
-
});
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
/**
|
|
689
|
-
* Handle virtual keyboard appearance/disappearance
|
|
690
|
-
* @private
|
|
691
|
-
*/
|
|
692
|
-
}, {
|
|
693
|
-
key: "_handleVirtualKeyboard",
|
|
694
|
-
value: function _handleVirtualKeyboard() {
|
|
695
|
-
// Adjust layout when virtual keyboard appears
|
|
696
|
-
var keyboardHeight = window.innerHeight - window.visualViewport.height;
|
|
697
|
-
if (keyboardHeight > 0) {
|
|
698
|
-
// Keyboard is visible - adjust chat widget height
|
|
699
|
-
this._chatWidget.style.paddingBottom = "".concat(keyboardHeight, "px");
|
|
700
|
-
} else {
|
|
701
|
-
// Keyboard hidden - restore original padding
|
|
702
|
-
this._chatWidget.style.paddingBottom = '';
|
|
703
|
-
}
|
|
704
196
|
}
|
|
705
197
|
|
|
706
198
|
/**
|
|
@@ -709,40 +201,55 @@ var quikchat = /*#__PURE__*/function () {
|
|
|
709
201
|
}, {
|
|
710
202
|
key: "_attachEventListeners",
|
|
711
203
|
value: function _attachEventListeners() {
|
|
712
|
-
var
|
|
713
|
-
this._sendButton.addEventListener('click', function (
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
window.addEventListener('resize', function () {
|
|
718
|
-
return _this7._handleContainerResize();
|
|
719
|
-
});
|
|
720
|
-
this._chatWidget.addEventListener('resize', function () {
|
|
721
|
-
return _this7._handleContainerResize();
|
|
204
|
+
var _this = this;
|
|
205
|
+
this._sendButton.addEventListener('click', function () {
|
|
206
|
+
var text = _this._textEntry.value.trim();
|
|
207
|
+
if (text === '') return;
|
|
208
|
+
_this._onSend(_this, text);
|
|
722
209
|
});
|
|
723
210
|
this._textEntry.addEventListener('keydown', function (event) {
|
|
724
|
-
// Check if Shift + Enter is pressed
|
|
211
|
+
// Check if Shift + Enter is pressed
|
|
725
212
|
if (event.shiftKey && event.keyCode === 13) {
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
}
|
|
731
|
-
} else if (event.keyCode === 13) {
|
|
732
|
-
// Enter but not Shift + Enter
|
|
733
|
-
if (_this7.sendOnEnter) {
|
|
734
|
-
event.preventDefault();
|
|
735
|
-
_this7._onSend(_this7, _this7._textEntry.value.trim());
|
|
736
|
-
}
|
|
213
|
+
event.preventDefault();
|
|
214
|
+
var text = _this._textEntry.value.trim();
|
|
215
|
+
if (text === '') return;
|
|
216
|
+
_this._onSend(_this, text);
|
|
737
217
|
}
|
|
738
218
|
});
|
|
219
|
+
|
|
220
|
+
// Auto-grow textarea
|
|
221
|
+
this._textEntry.addEventListener('input', function () {
|
|
222
|
+
return _this._autoGrowTextarea();
|
|
223
|
+
});
|
|
739
224
|
this._messagesArea.addEventListener('scroll', function () {
|
|
740
|
-
var
|
|
741
|
-
scrollTop =
|
|
742
|
-
scrollHeight =
|
|
743
|
-
clientHeight =
|
|
744
|
-
|
|
225
|
+
var _this$_messagesArea = _this._messagesArea,
|
|
226
|
+
scrollTop = _this$_messagesArea.scrollTop,
|
|
227
|
+
scrollHeight = _this$_messagesArea.scrollHeight,
|
|
228
|
+
clientHeight = _this$_messagesArea.clientHeight;
|
|
229
|
+
_this.userScrolledUp = scrollTop + clientHeight < scrollHeight - 1;
|
|
230
|
+
_this._updateScrollBottomBtn();
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// Scroll-to-bottom button
|
|
234
|
+
this._scrollBottomBtn.addEventListener('click', function () {
|
|
235
|
+
return _this.scrollToBottom();
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// Ctrl+End to scroll to bottom
|
|
239
|
+
this._chatWidget.addEventListener('keydown', function (event) {
|
|
240
|
+
if (event.ctrlKey && event.key === 'End') {
|
|
241
|
+
event.preventDefault();
|
|
242
|
+
_this.scrollToBottom();
|
|
243
|
+
}
|
|
745
244
|
});
|
|
245
|
+
|
|
246
|
+
// Use ResizeObserver to detect parent container resize
|
|
247
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
248
|
+
this._resizeObserver = new ResizeObserver(function () {
|
|
249
|
+
return _this._handleContainerResize();
|
|
250
|
+
});
|
|
251
|
+
this._resizeObserver.observe(this._parentElement);
|
|
252
|
+
}
|
|
746
253
|
}
|
|
747
254
|
|
|
748
255
|
// set the onSend function callback.
|
|
@@ -757,54 +264,16 @@ var quikchat = /*#__PURE__*/function () {
|
|
|
757
264
|
value: function setCallbackonMessageAdded(callback) {
|
|
758
265
|
this._onMessageAdded = callback;
|
|
759
266
|
}
|
|
760
|
-
|
|
761
|
-
/**
|
|
762
|
-
* Sets the callback function for when content is appended to a message
|
|
763
|
-
* @param {Function} callback - Function to call when content is appended
|
|
764
|
-
* @param {quikchat} callback.instance - The QuikChat instance
|
|
765
|
-
* @param {number} callback.msgId - The ID of the message being appended to
|
|
766
|
-
* @param {string} callback.content - The content being appended
|
|
767
|
-
* @since 1.1.15
|
|
768
|
-
* @example
|
|
769
|
-
* chat.setCallbackonMessageAppend((instance, msgId, content) => {
|
|
770
|
-
* console.log(`Appended "${content}" to message ${msgId}`);
|
|
771
|
-
* });
|
|
772
|
-
*/
|
|
773
267
|
}, {
|
|
774
268
|
key: "setCallbackonMessageAppend",
|
|
775
269
|
value: function setCallbackonMessageAppend(callback) {
|
|
776
270
|
this._onMessageAppend = callback;
|
|
777
271
|
}
|
|
778
|
-
|
|
779
|
-
/**
|
|
780
|
-
* Sets the callback function for when a message's content is replaced
|
|
781
|
-
* @param {Function} callback - Function to call when content is replaced
|
|
782
|
-
* @param {quikchat} callback.instance - The QuikChat instance
|
|
783
|
-
* @param {number} callback.msgId - The ID of the message being replaced
|
|
784
|
-
* @param {string} callback.content - The new content
|
|
785
|
-
* @since 1.1.15
|
|
786
|
-
* @example
|
|
787
|
-
* chat.setCallbackonMessageReplace((instance, msgId, content) => {
|
|
788
|
-
* console.log(`Message ${msgId} replaced with: ${content}`);
|
|
789
|
-
* });
|
|
790
|
-
*/
|
|
791
272
|
}, {
|
|
792
273
|
key: "setCallbackonMessageReplace",
|
|
793
274
|
value: function setCallbackonMessageReplace(callback) {
|
|
794
275
|
this._onMessageReplace = callback;
|
|
795
276
|
}
|
|
796
|
-
|
|
797
|
-
/**
|
|
798
|
-
* Sets the callback function for when a message is deleted
|
|
799
|
-
* @param {Function} callback - Function to call when a message is deleted
|
|
800
|
-
* @param {quikchat} callback.instance - The QuikChat instance
|
|
801
|
-
* @param {number} callback.msgId - The ID of the deleted message
|
|
802
|
-
* @since 1.1.15
|
|
803
|
-
* @example
|
|
804
|
-
* chat.setCallbackonMessageDelete((instance, msgId) => {
|
|
805
|
-
* console.log(`Message ${msgId} was deleted`);
|
|
806
|
-
* });
|
|
807
|
-
*/
|
|
808
277
|
}, {
|
|
809
278
|
key: "setCallbackonMessageDelete",
|
|
810
279
|
value: function setCallbackonMessageDelete(callback) {
|
|
@@ -812,58 +281,32 @@ var quikchat = /*#__PURE__*/function () {
|
|
|
812
281
|
}
|
|
813
282
|
|
|
814
283
|
// Public methods
|
|
815
|
-
/**
|
|
816
|
-
* Toggles the visibility of the title area
|
|
817
|
-
* @returns {void}
|
|
818
|
-
*/
|
|
819
284
|
}, {
|
|
820
285
|
key: "titleAreaToggle",
|
|
821
286
|
value: function titleAreaToggle() {
|
|
822
|
-
this._titleArea.style.display === 'none'
|
|
287
|
+
if (this._titleArea.style.display === 'none') {
|
|
288
|
+
this.titleAreaShow();
|
|
289
|
+
} else {
|
|
290
|
+
this.titleAreaHide();
|
|
291
|
+
}
|
|
823
292
|
}
|
|
824
|
-
|
|
825
|
-
/**
|
|
826
|
-
* Shows the title area
|
|
827
|
-
* @returns {void}
|
|
828
|
-
*/
|
|
829
293
|
}, {
|
|
830
294
|
key: "titleAreaShow",
|
|
831
295
|
value: function titleAreaShow() {
|
|
832
296
|
this._titleArea.style.display = '';
|
|
833
|
-
this._adjustMessagesAreaHeight();
|
|
834
297
|
}
|
|
835
|
-
|
|
836
|
-
/**
|
|
837
|
-
* Hides the title area
|
|
838
|
-
* @returns {void}
|
|
839
|
-
*/
|
|
840
298
|
}, {
|
|
841
299
|
key: "titleAreaHide",
|
|
842
300
|
value: function titleAreaHide() {
|
|
843
301
|
this._titleArea.style.display = 'none';
|
|
844
|
-
this._adjustMessagesAreaHeight();
|
|
845
302
|
}
|
|
846
|
-
|
|
847
|
-
/**
|
|
848
|
-
* Sets the contents of the title area
|
|
849
|
-
* @param {string} title - HTML content to display in the title area
|
|
850
|
-
* @param {'left'|'center'|'right'} [align='center'] - Text alignment
|
|
851
|
-
* @returns {void}
|
|
852
|
-
* @example
|
|
853
|
-
* chat.titleAreaSetContents('<h2>Support Chat</h2>', 'center');
|
|
854
|
-
*/
|
|
855
303
|
}, {
|
|
856
304
|
key: "titleAreaSetContents",
|
|
857
305
|
value: function titleAreaSetContents(title) {
|
|
858
306
|
var align = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'center';
|
|
859
|
-
this._titleArea.innerHTML =
|
|
307
|
+
this._titleArea.innerHTML = title;
|
|
860
308
|
this._titleArea.style.textAlign = align;
|
|
861
309
|
}
|
|
862
|
-
|
|
863
|
-
/**
|
|
864
|
-
* Gets the current contents of the title area
|
|
865
|
-
* @returns {string} The HTML content of the title area
|
|
866
|
-
*/
|
|
867
310
|
}, {
|
|
868
311
|
key: "titleAreaGetContents",
|
|
869
312
|
value: function titleAreaGetContents() {
|
|
@@ -872,48 +315,133 @@ var quikchat = /*#__PURE__*/function () {
|
|
|
872
315
|
}, {
|
|
873
316
|
key: "inputAreaToggle",
|
|
874
317
|
value: function inputAreaToggle() {
|
|
875
|
-
this._inputArea.
|
|
876
|
-
|
|
318
|
+
if (this._inputArea.style.display === 'none') {
|
|
319
|
+
this.inputAreaShow();
|
|
320
|
+
} else {
|
|
321
|
+
this.inputAreaHide();
|
|
322
|
+
}
|
|
877
323
|
}
|
|
878
324
|
}, {
|
|
879
325
|
key: "inputAreaShow",
|
|
880
326
|
value: function inputAreaShow() {
|
|
881
327
|
this._inputArea.style.display = '';
|
|
882
|
-
this._adjustMessagesAreaHeight();
|
|
883
328
|
}
|
|
884
329
|
}, {
|
|
885
330
|
key: "inputAreaHide",
|
|
886
331
|
value: function inputAreaHide() {
|
|
887
332
|
this._inputArea.style.display = 'none';
|
|
888
|
-
this._adjustMessagesAreaHeight();
|
|
889
333
|
}
|
|
890
334
|
}, {
|
|
891
|
-
key: "
|
|
892
|
-
value: function
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
335
|
+
key: "inputAreaSetEnabled",
|
|
336
|
+
value: function inputAreaSetEnabled(enabled) {
|
|
337
|
+
this._textEntry.disabled = !enabled;
|
|
338
|
+
this._sendButton.disabled = !enabled;
|
|
339
|
+
}
|
|
340
|
+
}, {
|
|
341
|
+
key: "inputAreaSetButtonText",
|
|
342
|
+
value: function inputAreaSetButtonText(text) {
|
|
343
|
+
this._sendButton.textContent = text;
|
|
344
|
+
}
|
|
345
|
+
}, {
|
|
346
|
+
key: "inputAreaGetButtonText",
|
|
347
|
+
value: function inputAreaGetButtonText() {
|
|
348
|
+
return this._sendButton.textContent;
|
|
349
|
+
}
|
|
350
|
+
}, {
|
|
351
|
+
key: "setDirection",
|
|
352
|
+
value: function setDirection(dir) {
|
|
353
|
+
var d = dir === 'rtl' ? 'rtl' : 'ltr';
|
|
354
|
+
this._chatWidget.setAttribute('dir', d);
|
|
355
|
+
if (d === 'rtl') {
|
|
356
|
+
this._chatWidget.classList.add('quikchat-rtl');
|
|
357
|
+
} else {
|
|
358
|
+
this._chatWidget.classList.remove('quikchat-rtl');
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}, {
|
|
362
|
+
key: "getDirection",
|
|
363
|
+
value: function getDirection() {
|
|
364
|
+
return this._chatWidget.getAttribute('dir') || 'ltr';
|
|
901
365
|
}
|
|
902
366
|
}, {
|
|
903
367
|
key: "_handleContainerResize",
|
|
904
368
|
value: function _handleContainerResize() {
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
return true;
|
|
369
|
+
// Layout is handled by CSS flexbox — no JS height calculation needed.
|
|
370
|
+
// This hook exists for future use or custom resize callbacks.
|
|
908
371
|
}
|
|
909
372
|
}, {
|
|
910
|
-
key: "
|
|
911
|
-
value: function
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
373
|
+
key: "scrollToBottom",
|
|
374
|
+
value: function scrollToBottom() {
|
|
375
|
+
this._messagesArea.scrollTop = this._messagesArea.scrollHeight;
|
|
376
|
+
this.userScrolledUp = false;
|
|
377
|
+
this._updateScrollBottomBtn();
|
|
378
|
+
}
|
|
379
|
+
}, {
|
|
380
|
+
key: "_updateScrollBottomBtn",
|
|
381
|
+
value: function _updateScrollBottomBtn() {
|
|
382
|
+
if (this.userScrolledUp) {
|
|
383
|
+
this._scrollBottomBtn.classList.add('quikchat-scroll-bottom-visible');
|
|
384
|
+
} else {
|
|
385
|
+
this._scrollBottomBtn.classList.remove('quikchat-scroll-bottom-visible');
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}, {
|
|
389
|
+
key: "_autoGrowTextarea",
|
|
390
|
+
value: function _autoGrowTextarea() {
|
|
391
|
+
var el = this._textEntry;
|
|
392
|
+
el.style.height = 'auto';
|
|
393
|
+
var maxHeight = parseInt(getComputedStyle(el).getPropertyValue('--quikchat-input-max-height')) || 120;
|
|
394
|
+
el.style.height = Math.min(el.scrollHeight, maxHeight) + 'px';
|
|
395
|
+
el.style.overflowY = el.scrollHeight > maxHeight ? 'auto' : 'hidden';
|
|
396
|
+
}
|
|
397
|
+
}, {
|
|
398
|
+
key: "_formatTimestamp",
|
|
399
|
+
value: function _formatTimestamp(isoString) {
|
|
400
|
+
var d = new Date(isoString);
|
|
401
|
+
var h = d.getHours();
|
|
402
|
+
var m = String(d.getMinutes()).padStart(2, '0');
|
|
403
|
+
var ampm = h >= 12 ? 'PM' : 'AM';
|
|
404
|
+
var h12 = h % 12 || 12;
|
|
405
|
+
return h12 + ':' + m + ' ' + ampm;
|
|
406
|
+
}
|
|
407
|
+
}, {
|
|
408
|
+
key: "messagesAreaShowTimestamps",
|
|
409
|
+
value: function messagesAreaShowTimestamps(show) {
|
|
410
|
+
if (show) {
|
|
411
|
+
this._messagesArea.classList.add('quikchat-show-timestamps');
|
|
412
|
+
} else {
|
|
413
|
+
this._messagesArea.classList.remove('quikchat-show-timestamps');
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}, {
|
|
417
|
+
key: "messagesAreaShowTimestampsGet",
|
|
418
|
+
value: function messagesAreaShowTimestampsGet() {
|
|
419
|
+
return this._messagesArea.classList.contains('quikchat-show-timestamps');
|
|
420
|
+
}
|
|
421
|
+
}, {
|
|
422
|
+
key: "messagesAreaShowTimestampsToggle",
|
|
423
|
+
value: function messagesAreaShowTimestampsToggle() {
|
|
424
|
+
this._messagesArea.classList.toggle('quikchat-show-timestamps');
|
|
425
|
+
}
|
|
426
|
+
}, {
|
|
427
|
+
key: "_escapeHTML",
|
|
428
|
+
value: function _escapeHTML(str) {
|
|
429
|
+
var div = document.createElement('div');
|
|
430
|
+
div.textContent = str;
|
|
431
|
+
return div.innerHTML;
|
|
432
|
+
}
|
|
433
|
+
}, {
|
|
434
|
+
key: "_processContent",
|
|
435
|
+
value: function _processContent(content) {
|
|
436
|
+
if (this._sanitize === true) {
|
|
437
|
+
content = this._escapeHTML(content);
|
|
438
|
+
} else if (typeof this._sanitize === 'function') {
|
|
439
|
+
content = this._sanitize(content);
|
|
440
|
+
}
|
|
441
|
+
if (this._messageFormatter) {
|
|
442
|
+
content = this._messageFormatter(content);
|
|
443
|
+
}
|
|
444
|
+
return content;
|
|
917
445
|
}
|
|
918
446
|
|
|
919
447
|
//messagesArea functions
|
|
@@ -938,151 +466,67 @@ var quikchat = /*#__PURE__*/function () {
|
|
|
938
466
|
value: function messagesAreaAlternateColorsGet() {
|
|
939
467
|
return this._messagesArea.classList.contains('quikchat-messages-area-alt');
|
|
940
468
|
}
|
|
941
|
-
|
|
942
|
-
* Adds a new message to the chat with full configuration options
|
|
943
|
-
* @param {Object} input - Message configuration object
|
|
944
|
-
* @param {string} [input.content=''] - Message content (HTML allowed)
|
|
945
|
-
* @param {string} [input.userString='user'] - Display name for the message sender
|
|
946
|
-
* @param {'left'|'right'|'center'} [input.align='right'] - Message alignment
|
|
947
|
-
* @param {string} [input.role='user'] - Role identifier (user, assistant, system)
|
|
948
|
-
* @param {number} [input.userID=-1] - User ID for the message
|
|
949
|
-
* @param {string|false} [input.timestamp=false] - ISO timestamp or false for auto
|
|
950
|
-
* @param {string|false} [input.updatedtime=false] - Last updated timestamp
|
|
951
|
-
* @param {boolean|'smart'} [input.scrollIntoView=true] - Scroll behavior (true/false/'smart')
|
|
952
|
-
* @param {boolean} [input.visible=true] - Whether message is initially visible
|
|
953
|
-
* @param {string[]} [input.tags=[]] - Tags for message categorization
|
|
954
|
-
* @returns {number} Message ID for the newly added message
|
|
955
|
-
* @example
|
|
956
|
-
* const msgId = chat.messageAddFull({
|
|
957
|
-
* content: 'Hello!',
|
|
958
|
-
* userString: 'Bot',
|
|
959
|
-
* align: 'left',
|
|
960
|
-
* scrollIntoView: 'smart',
|
|
961
|
-
* tags: ['greeting']
|
|
962
|
-
* });
|
|
963
|
-
*/
|
|
469
|
+
// message functions
|
|
964
470
|
}, {
|
|
965
471
|
key: "messageAddFull",
|
|
966
472
|
value: function messageAddFull() {
|
|
967
|
-
var _this8 = this;
|
|
968
473
|
var input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
|
|
969
474
|
content: "",
|
|
970
475
|
userString: "user",
|
|
971
476
|
align: "right",
|
|
972
477
|
role: "user",
|
|
973
|
-
userID: -1
|
|
974
|
-
timestamp: false,
|
|
975
|
-
updatedtime: false,
|
|
976
|
-
scrollIntoView: true,
|
|
977
|
-
visible: true,
|
|
978
|
-
tags: []
|
|
478
|
+
userID: -1
|
|
979
479
|
};
|
|
980
480
|
var msgid = this.msgid;
|
|
481
|
+
var messageDiv = document.createElement('div');
|
|
482
|
+
var msgidClass = 'quikchat-msgid-' + String(msgid).padStart(10, '0');
|
|
483
|
+
messageDiv.classList.add('quikchat-message', msgidClass);
|
|
484
|
+
messageDiv.classList.add('quikchat-role-' + (input.role || 'user'));
|
|
485
|
+
messageDiv.classList.add('quikchat-align-' + (input.align || 'right'));
|
|
981
486
|
this.msgid++;
|
|
982
|
-
|
|
487
|
+
messageDiv.classList.add(this._messagesArea.children.length % 2 === 1 ? 'quikchat-message-1' : 'quikchat-message-2');
|
|
983
488
|
|
|
984
|
-
//
|
|
985
|
-
|
|
986
|
-
|
|
489
|
+
// Visibility: default true, hidden messages get display:none
|
|
490
|
+
var visible = input.visible !== false;
|
|
491
|
+
if (!visible) {
|
|
492
|
+
messageDiv.style.display = 'none';
|
|
987
493
|
}
|
|
988
494
|
|
|
989
|
-
//
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
}
|
|
1008
|
-
});
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
|
-
// Add to virtual scroller
|
|
1012
|
-
this.virtualScroller.addItem(messageData);
|
|
1013
|
-
|
|
1014
|
-
// Clear text entry
|
|
1015
|
-
this._textEntry.value = '';
|
|
1016
|
-
this._adjustMessagesAreaHeight();
|
|
1017
|
-
} else {
|
|
1018
|
-
// Original DOM-based implementation
|
|
1019
|
-
messageDiv = document.createElement('div');
|
|
1020
|
-
var msgidClass = 'quikchat-msgid-' + String(msgid).padStart(10, '0');
|
|
1021
|
-
'quikchat-userid-' + String(input.userString).padStart(10, '0'); // hash this..
|
|
1022
|
-
messageDiv.classList.add('quikchat-message', msgidClass, 'quikchat-structure');
|
|
1023
|
-
messageDiv.setAttribute('role', 'article');
|
|
1024
|
-
messageDiv.setAttribute('aria-label', "Message from ".concat(input.userString || 'user'));
|
|
1025
|
-
if (Array.isArray(input.tags)) {
|
|
1026
|
-
input.tags.forEach(function (tag) {
|
|
1027
|
-
if (typeof tag === 'string' && /^[a-zA-Z0-9-]+$/.test(tag)) {
|
|
1028
|
-
messageDiv.classList.add("quikchat-tag-".concat(tag));
|
|
1029
|
-
_this8._activeTags.add(tag);
|
|
1030
|
-
}
|
|
1031
|
-
});
|
|
1032
|
-
}
|
|
1033
|
-
var userDiv = document.createElement('div');
|
|
1034
|
-
userDiv.innerHTML = this._sanitizeContent(input.userString);
|
|
1035
|
-
userDiv.classList.add('quikchat-user-label');
|
|
1036
|
-
userDiv.style.textAlign = input.align;
|
|
1037
|
-
var contentDiv = document.createElement('div');
|
|
1038
|
-
contentDiv.classList.add('quikchat-message-content');
|
|
1039
|
-
|
|
1040
|
-
// Determine text alignment for right-aligned messages
|
|
1041
|
-
if (input.align === "right") {
|
|
1042
|
-
var isMultiLine = input.content.includes("\n");
|
|
1043
|
-
var isLong = input.content.length > 50; // Adjust length threshold
|
|
1044
|
-
|
|
1045
|
-
if (isMultiLine || isLong) {
|
|
1046
|
-
contentDiv.classList.add("quikchat-right-multiline");
|
|
1047
|
-
} else {
|
|
1048
|
-
contentDiv.classList.add("quikchat-right-singleline");
|
|
1049
|
-
}
|
|
1050
|
-
}
|
|
1051
|
-
contentDiv.innerHTML = this._sanitizeContent(input.content);
|
|
1052
|
-
messageDiv.appendChild(userDiv);
|
|
1053
|
-
messageDiv.appendChild(contentDiv);
|
|
1054
|
-
this._messagesArea.appendChild(messageDiv);
|
|
1055
|
-
if (input.visible === false) {
|
|
1056
|
-
messageDiv.style.display = 'none';
|
|
1057
|
-
}
|
|
1058
|
-
|
|
1059
|
-
// Handle scroll behavior based on scrollIntoView parameter
|
|
1060
|
-
// 'smart' = only scroll if near bottom, true = always scroll, false = never scroll
|
|
1061
|
-
if (input.scrollIntoView === true) {
|
|
1062
|
-
this.messageScrollToBottom();
|
|
1063
|
-
} else if (input.scrollIntoView === 'smart' && !this.userScrolledUp) {
|
|
1064
|
-
this.messageScrollToBottom();
|
|
1065
|
-
}
|
|
1066
|
-
// If scrollIntoView is false, don't scroll at all
|
|
495
|
+
// Tags: array of strings for group-based visibility control
|
|
496
|
+
var tags = Array.isArray(input.tags) ? input.tags.slice() : [];
|
|
497
|
+
var userDiv = document.createElement('div');
|
|
498
|
+
userDiv.classList.add('quikchat-user-label');
|
|
499
|
+
userDiv.style.textAlign = input.align;
|
|
500
|
+
userDiv.innerHTML = input.userString;
|
|
501
|
+
var contentDiv = document.createElement('div');
|
|
502
|
+
contentDiv.classList.add('quikchat-message-content');
|
|
503
|
+
contentDiv.style.textAlign = input.align;
|
|
504
|
+
contentDiv.innerHTML = this._processContent(input.content);
|
|
505
|
+
var timestamp = new Date().toISOString();
|
|
506
|
+
var timestampSpan = document.createElement('span');
|
|
507
|
+
timestampSpan.classList.add('quikchat-timestamp');
|
|
508
|
+
timestampSpan.textContent = this._formatTimestamp(timestamp);
|
|
509
|
+
messageDiv.appendChild(userDiv);
|
|
510
|
+
messageDiv.appendChild(contentDiv);
|
|
511
|
+
messageDiv.appendChild(timestampSpan);
|
|
512
|
+
this._messagesArea.appendChild(messageDiv);
|
|
1067
513
|
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
this.
|
|
1071
|
-
this._updateMessageStyles();
|
|
514
|
+
// Scroll to the last message only if the user is not actively scrolling up
|
|
515
|
+
if (!this.userScrolledUp) {
|
|
516
|
+
this._messagesArea.scrollTop = this._messagesArea.scrollHeight;
|
|
1072
517
|
}
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
var
|
|
1076
|
-
var updatedtime = input.updatedtime ? input.updatedtime : timestamp;
|
|
1077
|
-
var visible = input.visible !== undefined ? input.visible : true;
|
|
518
|
+
this._textEntry.value = '';
|
|
519
|
+
this._autoGrowTextarea();
|
|
520
|
+
var updatedtime = timestamp;
|
|
1078
521
|
if (this.trackHistory) {
|
|
1079
522
|
this._history.push(_objectSpread2(_objectSpread2({
|
|
1080
523
|
msgid: msgid
|
|
1081
524
|
}, input), {}, {
|
|
1082
525
|
visible: visible,
|
|
526
|
+
tags: tags,
|
|
1083
527
|
timestamp: timestamp,
|
|
1084
528
|
updatedtime: updatedtime,
|
|
1085
|
-
messageDiv: messageDiv
|
|
529
|
+
messageDiv: messageDiv
|
|
1086
530
|
}));
|
|
1087
531
|
if (this._history.length > this._historyLimit) {
|
|
1088
532
|
this._history.shift();
|
|
@@ -1093,24 +537,6 @@ var quikchat = /*#__PURE__*/function () {
|
|
|
1093
537
|
}
|
|
1094
538
|
return msgid;
|
|
1095
539
|
}
|
|
1096
|
-
|
|
1097
|
-
/**
|
|
1098
|
-
* Adds a new message to the chat (simplified version of messageAddFull)
|
|
1099
|
-
* @param {string} [content=''] - Message content (HTML allowed)
|
|
1100
|
-
* @param {string} [userString='user'] - Display name for the message sender
|
|
1101
|
-
* @param {'left'|'right'|'center'} [align='right'] - Message alignment
|
|
1102
|
-
* @param {string} [role='user'] - Role identifier (user, assistant, system)
|
|
1103
|
-
* @param {boolean|'smart'} [scrollIntoView=true] - Scroll behavior
|
|
1104
|
-
* @param {boolean} [visible=true] - Whether message is initially visible
|
|
1105
|
-
* @param {string[]} [tags=[]] - Tags for message categorization
|
|
1106
|
-
* @returns {number} Message ID for the newly added message
|
|
1107
|
-
* @example
|
|
1108
|
-
* // Simple message
|
|
1109
|
-
* chat.messageAddNew('Hello!', 'User', 'right');
|
|
1110
|
-
*
|
|
1111
|
-
* // Bot message with smart scroll
|
|
1112
|
-
* chat.messageAddNew('Hi there!', 'Bot', 'left', 'assistant', 'smart');
|
|
1113
|
-
*/
|
|
1114
540
|
}, {
|
|
1115
541
|
key: "messageAddNew",
|
|
1116
542
|
value: function messageAddNew() {
|
|
@@ -1118,115 +544,125 @@ var quikchat = /*#__PURE__*/function () {
|
|
|
1118
544
|
var userString = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "user";
|
|
1119
545
|
var align = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "right";
|
|
1120
546
|
var role = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : "user";
|
|
1121
|
-
|
|
1122
|
-
var visible = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : true;
|
|
1123
|
-
var tags = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : [];
|
|
1124
|
-
var retvalue = this.messageAddFull({
|
|
547
|
+
return this.messageAddFull({
|
|
1125
548
|
content: content,
|
|
1126
549
|
userString: userString,
|
|
1127
550
|
align: align,
|
|
1128
|
-
role: role
|
|
1129
|
-
scrollIntoView: scrollIntoView,
|
|
1130
|
-
visible: visible,
|
|
1131
|
-
tags: tags
|
|
551
|
+
role: role
|
|
1132
552
|
});
|
|
1133
|
-
// this.messageScrollToBottom();
|
|
1134
|
-
return retvalue;
|
|
1135
553
|
}
|
|
1136
|
-
|
|
1137
|
-
/**
|
|
1138
|
-
* Removes a message from the chat by its ID
|
|
1139
|
-
* @param {number} n - Message ID to remove
|
|
1140
|
-
* @returns {boolean} True if message was removed, false if not found
|
|
1141
|
-
* @example
|
|
1142
|
-
* const success = chat.messageRemove(5);
|
|
1143
|
-
*/
|
|
1144
554
|
}, {
|
|
1145
555
|
key: "messageRemove",
|
|
1146
556
|
value: function messageRemove(n) {
|
|
1147
|
-
|
|
1148
|
-
var sucess = false;
|
|
557
|
+
var success = false;
|
|
1149
558
|
try {
|
|
1150
559
|
this._messagesArea.removeChild(this._messagesArea.querySelector(".quikchat-msgid-".concat(String(n).padStart(10, '0'))));
|
|
1151
|
-
|
|
1152
|
-
} catch (
|
|
1153
|
-
|
|
560
|
+
success = true;
|
|
561
|
+
} catch (_error) {
|
|
562
|
+
// Message ID not found
|
|
1154
563
|
}
|
|
1155
|
-
if (
|
|
1156
|
-
// slow way to remove from history
|
|
1157
|
-
//this._history = this._history.filter((item) => item.msgid !== n); // todo make this more efficient
|
|
1158
|
-
|
|
1159
|
-
// better way to delete this from history
|
|
564
|
+
if (success) {
|
|
1160
565
|
this._history.splice(this._history.findIndex(function (item) {
|
|
1161
566
|
return item.msgid === n;
|
|
1162
567
|
}), 1);
|
|
1163
|
-
|
|
1164
|
-
// Call the onMessageDelete callback if it exists
|
|
1165
568
|
if (this._onMessageDelete) {
|
|
1166
569
|
this._onMessageDelete(this, n);
|
|
1167
570
|
}
|
|
1168
571
|
}
|
|
1169
|
-
return
|
|
572
|
+
return success;
|
|
1170
573
|
}
|
|
1171
574
|
/* returns the message html object from the DOM
|
|
1172
575
|
*/
|
|
1173
|
-
/**
|
|
1174
|
-
* Gets the DOM element for a message by its ID
|
|
1175
|
-
* @param {number} n - Message ID
|
|
1176
|
-
* @returns {HTMLElement|null} The message DOM element or null if not found
|
|
1177
|
-
*/
|
|
1178
576
|
}, {
|
|
1179
577
|
key: "messageGetDOMObject",
|
|
1180
578
|
value: function messageGetDOMObject(n) {
|
|
1181
579
|
var msg = null;
|
|
1182
|
-
// now use css selector to get the message
|
|
1183
580
|
try {
|
|
1184
581
|
msg = this._messagesArea.querySelector(".quikchat-msgid-".concat(String(n).padStart(10, '0')));
|
|
1185
|
-
} catch (
|
|
1186
|
-
|
|
582
|
+
} catch (_error) {
|
|
583
|
+
// Message ID not found
|
|
1187
584
|
}
|
|
1188
585
|
return msg;
|
|
1189
586
|
}
|
|
1190
587
|
/* returns the message content only
|
|
1191
588
|
*/
|
|
1192
|
-
/**
|
|
1193
|
-
* Gets the content of a message by its ID
|
|
1194
|
-
* @param {number} n - Message ID
|
|
1195
|
-
* @returns {string} The message content or empty string if not found
|
|
1196
|
-
*/
|
|
1197
589
|
}, {
|
|
1198
590
|
key: "messageGetContent",
|
|
1199
591
|
value: function messageGetContent(n) {
|
|
1200
592
|
var content = "";
|
|
1201
|
-
// now use css selector to get the message
|
|
1202
593
|
try {
|
|
1203
|
-
// get from history..
|
|
1204
594
|
content = this._history.filter(function (item) {
|
|
1205
595
|
return item.msgid === n;
|
|
1206
596
|
})[0].content;
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
console.log("{String(n)} : Message ID not found");
|
|
597
|
+
} catch (_error) {
|
|
598
|
+
// Message ID not found
|
|
1210
599
|
}
|
|
1211
600
|
return content;
|
|
1212
601
|
}
|
|
1213
|
-
|
|
1214
|
-
/* returns the DOM Content element of a given message
|
|
1215
|
-
*/
|
|
1216
602
|
}, {
|
|
1217
|
-
key: "
|
|
1218
|
-
value: function
|
|
1219
|
-
var
|
|
1220
|
-
|
|
603
|
+
key: "messageSetVisible",
|
|
604
|
+
value: function messageSetVisible(n, visible) {
|
|
605
|
+
var msgEl = this.messageGetDOMObject(n);
|
|
606
|
+
if (!msgEl) return false;
|
|
607
|
+
msgEl.style.display = visible ? '' : 'none';
|
|
608
|
+
var item = this._history.find(function (entry) {
|
|
609
|
+
return entry.msgid === n;
|
|
610
|
+
});
|
|
611
|
+
if (item) item.visible = visible;
|
|
612
|
+
return true;
|
|
613
|
+
}
|
|
614
|
+
}, {
|
|
615
|
+
key: "messageGetVisible",
|
|
616
|
+
value: function messageGetVisible(n) {
|
|
617
|
+
var item = this._history.find(function (entry) {
|
|
618
|
+
return entry.msgid === n;
|
|
619
|
+
});
|
|
620
|
+
return item ? item.visible !== false : false;
|
|
621
|
+
}
|
|
622
|
+
}, {
|
|
623
|
+
key: "messageToggleVisible",
|
|
624
|
+
value: function messageToggleVisible(n) {
|
|
625
|
+
var current = this.messageGetVisible(n);
|
|
626
|
+
return this.messageSetVisible(n, !current);
|
|
627
|
+
}
|
|
628
|
+
}, {
|
|
629
|
+
key: "messageSetVisibleByTag",
|
|
630
|
+
value: function messageSetVisibleByTag(tag, visible) {
|
|
631
|
+
var count = 0;
|
|
632
|
+
var _iterator = _createForOfIteratorHelper(this._history),
|
|
633
|
+
_step;
|
|
1221
634
|
try {
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
635
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
636
|
+
var item = _step.value;
|
|
637
|
+
if (item.tags && item.tags.includes(tag)) {
|
|
638
|
+
this.messageSetVisible(item.msgid, visible);
|
|
639
|
+
count++;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
} catch (err) {
|
|
643
|
+
_iterator.e(err);
|
|
644
|
+
} finally {
|
|
645
|
+
_iterator.f();
|
|
1228
646
|
}
|
|
1229
|
-
return
|
|
647
|
+
return count;
|
|
648
|
+
}
|
|
649
|
+
}, {
|
|
650
|
+
key: "messageGetTags",
|
|
651
|
+
value: function messageGetTags(n) {
|
|
652
|
+
var item = this._history.find(function (entry) {
|
|
653
|
+
return entry.msgid === n;
|
|
654
|
+
});
|
|
655
|
+
return item && item.tags ? item.tags.slice() : [];
|
|
656
|
+
}
|
|
657
|
+
}, {
|
|
658
|
+
key: "messageSetTags",
|
|
659
|
+
value: function messageSetTags(n, tags) {
|
|
660
|
+
var item = this._history.find(function (entry) {
|
|
661
|
+
return entry.msgid === n;
|
|
662
|
+
});
|
|
663
|
+
if (!item) return false;
|
|
664
|
+
item.tags = Array.isArray(tags) ? tags.slice() : [];
|
|
665
|
+
return true;
|
|
1230
666
|
}
|
|
1231
667
|
|
|
1232
668
|
/* append message to the message content
|
|
@@ -1236,41 +672,23 @@ var quikchat = /*#__PURE__*/function () {
|
|
|
1236
672
|
value: function messageAppendContent(n, content) {
|
|
1237
673
|
var success = false;
|
|
1238
674
|
try {
|
|
1239
|
-
|
|
1240
|
-
var item = this._history.filter(function (
|
|
1241
|
-
return
|
|
675
|
+
var msgEl = this._messagesArea.querySelector(".quikchat-msgid-".concat(String(n).padStart(10, '0')));
|
|
676
|
+
var item = this._history.filter(function (entry) {
|
|
677
|
+
return entry.msgid === n;
|
|
1242
678
|
})[0];
|
|
1243
679
|
item.content += content;
|
|
1244
680
|
item.updatedtime = new Date().toISOString();
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
if (this.virtualScroller) {
|
|
1248
|
-
// Find the item index in virtual scroller
|
|
1249
|
-
var index = this.virtualScroller.items.findIndex(function (item) {
|
|
1250
|
-
return item.msgid === n;
|
|
1251
|
-
});
|
|
1252
|
-
if (index >= 0) {
|
|
1253
|
-
this.virtualScroller.items[index].content += content; // Don't double-sanitize, it's done on render
|
|
1254
|
-
// Re-render if the item is currently visible
|
|
1255
|
-
this.virtualScroller.updateItem(index, {
|
|
1256
|
-
content: this.virtualScroller.items[index].content
|
|
1257
|
-
});
|
|
1258
|
-
}
|
|
1259
|
-
} else {
|
|
1260
|
-
// Regular DOM manipulation
|
|
1261
|
-
this._messagesArea.querySelector(".quikchat-msgid-".concat(String(n).padStart(10, '0'))).lastChild.innerHTML += this._sanitizeContent(content);
|
|
1262
|
-
}
|
|
681
|
+
msgEl.querySelector('.quikchat-message-content').innerHTML = this._processContent(item.content);
|
|
682
|
+
msgEl.classList.remove('quikchat-typing');
|
|
1263
683
|
success = true;
|
|
1264
|
-
|
|
1265
|
-
|
|
684
|
+
if (!this.userScrolledUp) {
|
|
685
|
+
this._messagesArea.scrollTop = this._messagesArea.scrollHeight;
|
|
686
|
+
}
|
|
1266
687
|
if (this._onMessageAppend) {
|
|
1267
688
|
this._onMessageAppend(this, n, content);
|
|
1268
689
|
}
|
|
1269
|
-
|
|
1270
|
-
//
|
|
1271
|
-
// Users can call messageScrollToBottom() if they want to scroll
|
|
1272
|
-
} catch (error) {
|
|
1273
|
-
console.log("".concat(String(n), " : Message ID not found"));
|
|
690
|
+
} catch (_error) {
|
|
691
|
+
// Message ID not found
|
|
1274
692
|
}
|
|
1275
693
|
return success;
|
|
1276
694
|
}
|
|
@@ -1282,405 +700,80 @@ var quikchat = /*#__PURE__*/function () {
|
|
|
1282
700
|
value: function messageReplaceContent(n, content) {
|
|
1283
701
|
var success = false;
|
|
1284
702
|
try {
|
|
1285
|
-
|
|
1286
|
-
var item = this._history.filter(function (
|
|
1287
|
-
return
|
|
703
|
+
var msgEl = this._messagesArea.querySelector(".quikchat-msgid-".concat(String(n).padStart(10, '0')));
|
|
704
|
+
var item = this._history.filter(function (entry) {
|
|
705
|
+
return entry.msgid === n;
|
|
1288
706
|
})[0];
|
|
1289
707
|
item.content = content;
|
|
1290
708
|
item.updatedtime = new Date().toISOString();
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
if (this.virtualScroller) {
|
|
1294
|
-
// Find the item index in virtual scroller
|
|
1295
|
-
var index = this.virtualScroller.items.findIndex(function (item) {
|
|
1296
|
-
return item.msgid === n;
|
|
1297
|
-
});
|
|
1298
|
-
if (index >= 0) {
|
|
1299
|
-
this.virtualScroller.items[index].content = content; // Don't double-sanitize, it's done on render
|
|
1300
|
-
// Re-render if the item is currently visible
|
|
1301
|
-
this.virtualScroller.updateItem(index, {
|
|
1302
|
-
content: content
|
|
1303
|
-
});
|
|
1304
|
-
}
|
|
1305
|
-
} else {
|
|
1306
|
-
// Regular DOM manipulation
|
|
1307
|
-
this._messagesArea.querySelector(".quikchat-msgid-".concat(String(n).padStart(10, '0'))).lastChild.innerHTML = this._sanitizeContent(content);
|
|
1308
|
-
}
|
|
709
|
+
msgEl.querySelector('.quikchat-message-content').innerHTML = this._processContent(content);
|
|
710
|
+
msgEl.classList.remove('quikchat-typing');
|
|
1309
711
|
success = true;
|
|
1310
|
-
|
|
1311
|
-
|
|
712
|
+
if (!this.userScrolledUp) {
|
|
713
|
+
this._messagesArea.scrollTop = this._messagesArea.scrollHeight;
|
|
714
|
+
}
|
|
1312
715
|
if (this._onMessageReplace) {
|
|
1313
716
|
this._onMessageReplace(this, n, content);
|
|
1314
717
|
}
|
|
1315
|
-
|
|
1316
|
-
//
|
|
1317
|
-
// Users can call messageScrollToBottom() if they want to scroll
|
|
1318
|
-
} catch (error) {
|
|
1319
|
-
console.log("".concat(String(n), " : Message ID not found"));
|
|
718
|
+
} catch (_error) {
|
|
719
|
+
// Message ID not found
|
|
1320
720
|
}
|
|
1321
721
|
return success;
|
|
1322
722
|
}
|
|
1323
|
-
|
|
1324
|
-
/**
|
|
1325
|
-
* Scrolls the messages area to the bottom.
|
|
1326
|
-
*/
|
|
1327
|
-
}, {
|
|
1328
|
-
key: "messageScrollToBottom",
|
|
1329
|
-
value: function messageScrollToBottom() {
|
|
1330
|
-
// Always use scrollTop to avoid page jumping
|
|
1331
|
-
// This ensures only the chat container scrolls, not the entire page
|
|
1332
|
-
this._messagesArea.scrollTop = this._messagesArea.scrollHeight;
|
|
1333
|
-
}
|
|
1334
|
-
|
|
1335
|
-
/**
|
|
1336
|
-
* Removes the last message from the messages area.
|
|
1337
|
-
*/
|
|
1338
|
-
}, {
|
|
1339
|
-
key: "messageRemoveLast",
|
|
1340
|
-
value: function messageRemoveLast() {
|
|
1341
|
-
// find the last message by id:
|
|
1342
|
-
if (this._history.length >= 0) {
|
|
1343
|
-
var lastMsgId = this._history[this._history.length - 1].msgid;
|
|
1344
|
-
return this.messageRemove(lastMsgId);
|
|
1345
|
-
}
|
|
1346
|
-
return false;
|
|
1347
|
-
}
|
|
1348
723
|
}, {
|
|
1349
|
-
key: "
|
|
1350
|
-
value: function
|
|
1351
|
-
var
|
|
1352
|
-
|
|
724
|
+
key: "messageAddTypingIndicator",
|
|
725
|
+
value: function messageAddTypingIndicator() {
|
|
726
|
+
var userString = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
|
|
727
|
+
var align = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'left';
|
|
728
|
+
var msgid = this.messageAddFull({
|
|
729
|
+
content: '',
|
|
730
|
+
userString: userString,
|
|
731
|
+
align: align,
|
|
732
|
+
role: 'assistant'
|
|
1353
733
|
});
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
}
|
|
1360
|
-
return false;
|
|
734
|
+
var msgEl = this.messageGetDOMObject(msgid);
|
|
735
|
+
msgEl.classList.add('quikchat-typing');
|
|
736
|
+
var contentDiv = msgEl.querySelector('.quikchat-message-content');
|
|
737
|
+
contentDiv.innerHTML = '<span class="quikchat-typing-dots"><span>.</span><span>.</span><span>.</span></span>';
|
|
738
|
+
return msgid;
|
|
1361
739
|
}
|
|
1362
740
|
}, {
|
|
1363
|
-
key: "
|
|
1364
|
-
value: function
|
|
1365
|
-
|
|
1366
|
-
return item.msgid === msgid;
|
|
1367
|
-
});
|
|
1368
|
-
if (message && message.messageDiv) {
|
|
1369
|
-
return message.messageDiv.style.display !== 'none';
|
|
1370
|
-
}
|
|
1371
|
-
return false; // Return false if not found or no messageDiv
|
|
741
|
+
key: "setMessageFormatter",
|
|
742
|
+
value: function setMessageFormatter(formatter) {
|
|
743
|
+
this._messageFormatter = formatter;
|
|
1372
744
|
}
|
|
1373
745
|
}, {
|
|
1374
|
-
key: "
|
|
1375
|
-
value: function
|
|
1376
|
-
|
|
1377
|
-
return child.style.display !== 'none';
|
|
1378
|
-
});
|
|
1379
|
-
visibleMessages.forEach(function (messageDiv, index) {
|
|
1380
|
-
messageDiv.classList.remove('quikchat-message-1', 'quikchat-message-2');
|
|
1381
|
-
messageDiv.classList.add(index % 2 === 0 ? 'quikchat-message-1' : 'quikchat-message-2');
|
|
1382
|
-
});
|
|
746
|
+
key: "setSanitize",
|
|
747
|
+
value: function setSanitize(sanitize) {
|
|
748
|
+
this._sanitize = sanitize;
|
|
1383
749
|
}
|
|
1384
750
|
|
|
1385
|
-
/**
|
|
1386
|
-
* For right sided or centered messages, we need to handle the CSS for short and long messages.
|
|
1387
|
-
* for short messages we use simple justifying, for long messages we need to wrap and perform multiline
|
|
1388
|
-
* formatting.
|
|
1389
|
-
*
|
|
1390
|
-
* @param {*} messageElement
|
|
1391
|
-
* @returns nothing
|
|
1392
|
-
*/
|
|
1393
|
-
}, {
|
|
1394
|
-
key: "_handleShortLongMessageCSS",
|
|
1395
|
-
value: function _handleShortLongMessageCSS(messageElement, align) {
|
|
1396
|
-
// console.log(messageElement);
|
|
1397
|
-
// Reset classes
|
|
1398
|
-
messageElement.classList.remove('left-singleline', 'left-multiline', 'center-singleline', 'center-multiline', 'right-singleline', 'right-multiline');
|
|
1399
|
-
var contentDiv = messageElement.lastChild;
|
|
1400
|
-
window.lastDiv = contentDiv; // for debugging
|
|
1401
|
-
// Determine if the message is short or long
|
|
1402
|
-
|
|
1403
|
-
var computedStyle = window.getComputedStyle(contentDiv);
|
|
1404
|
-
|
|
1405
|
-
// Get the element's height
|
|
1406
|
-
var elementHeight = contentDiv.offsetHeight;
|
|
1407
|
-
|
|
1408
|
-
// Calculate or estimate line height
|
|
1409
|
-
var lineHeight;
|
|
1410
|
-
if (computedStyle.lineHeight === "normal") {
|
|
1411
|
-
var fontSize = parseFloat(computedStyle.fontSize);
|
|
1412
|
-
lineHeight = fontSize * 1.2; // approximate "normal" as 1.2 times font-size
|
|
1413
|
-
} else {
|
|
1414
|
-
lineHeight = parseFloat(computedStyle.lineHeight);
|
|
1415
|
-
}
|
|
1416
|
-
|
|
1417
|
-
// Check if the element height is more than one line-height
|
|
1418
|
-
var isMultiLine = elementHeight > lineHeight;
|
|
1419
|
-
|
|
1420
|
-
// Using scrollHeight and clientHeight to check for overflow (multi-line)
|
|
1421
|
-
switch (align) {
|
|
1422
|
-
case 'center':
|
|
1423
|
-
if (isMultiLine) {
|
|
1424
|
-
messageElement.classList.add('center-multiline');
|
|
1425
|
-
} else {
|
|
1426
|
-
messageElement.classList.add('center-singleline');
|
|
1427
|
-
}
|
|
1428
|
-
break;
|
|
1429
|
-
case 'right':
|
|
1430
|
-
if (isMultiLine) {
|
|
1431
|
-
messageElement.classList.add('right-multiline');
|
|
1432
|
-
} else {
|
|
1433
|
-
messageElement.classList.add('right-singleline');
|
|
1434
|
-
}
|
|
1435
|
-
break;
|
|
1436
|
-
case 'left':
|
|
1437
|
-
default:
|
|
1438
|
-
if (isMultiLine) {
|
|
1439
|
-
messageElement.classList.add('left-multiline');
|
|
1440
|
-
} else {
|
|
1441
|
-
messageElement.classList.add('left-singleline');
|
|
1442
|
-
}
|
|
1443
|
-
break;
|
|
1444
|
-
}
|
|
1445
|
-
}
|
|
1446
751
|
// history functions
|
|
1447
752
|
/**
|
|
1448
|
-
*
|
|
1449
|
-
* @param {*} n
|
|
1450
|
-
* @param {*} m
|
|
753
|
+
*
|
|
754
|
+
* @param {*} n
|
|
755
|
+
* @param {*} m
|
|
1451
756
|
* @returns array of history messages
|
|
1452
757
|
*/
|
|
1453
|
-
/**
|
|
1454
|
-
* Gets a slice of message history
|
|
1455
|
-
* @param {number} [n] - Start index (defaults to 0)
|
|
1456
|
-
* @param {number} [m] - End index (defaults to history length)
|
|
1457
|
-
* @returns {Array} Array of message objects
|
|
1458
|
-
* @example
|
|
1459
|
-
* // Get first 10 messages
|
|
1460
|
-
* const messages = chat.historyGet(0, 10);
|
|
1461
|
-
*
|
|
1462
|
-
* // Get all messages
|
|
1463
|
-
* const allMessages = chat.historyGet();
|
|
1464
|
-
*/
|
|
1465
758
|
}, {
|
|
1466
759
|
key: "historyGet",
|
|
1467
760
|
value: function historyGet(n, m) {
|
|
1468
|
-
if (n
|
|
1469
|
-
|
|
1470
|
-
m = this._history.length;
|
|
761
|
+
if (n === undefined) {
|
|
762
|
+
return this._history.slice();
|
|
1471
763
|
}
|
|
1472
764
|
if (m === undefined) {
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
// remember that entries could be deleted. TODO: So we need to return the actual history entries
|
|
1476
|
-
// so now we need to find the array index that correspondes to messageIds n (start) and m (end)
|
|
1477
|
-
|
|
1478
|
-
return this._history.slice(n, m);
|
|
1479
|
-
}
|
|
1480
|
-
|
|
1481
|
-
/**
|
|
1482
|
-
* Gets a copy of the entire message history
|
|
1483
|
-
* @returns {Array} Complete array of all message objects
|
|
1484
|
-
* @example
|
|
1485
|
-
* const history = chat.historyGetAllCopy();
|
|
1486
|
-
* console.log(`Total messages: ${history.length}`);
|
|
1487
|
-
*/
|
|
1488
|
-
}, {
|
|
1489
|
-
key: "historyGetAllCopy",
|
|
1490
|
-
value: function historyGetAllCopy() {
|
|
1491
|
-
return this._history.slice();
|
|
1492
|
-
}
|
|
1493
|
-
|
|
1494
|
-
/**
|
|
1495
|
-
* Get a page of history messages with pagination support
|
|
1496
|
-
* @param {number} page - Page number (1-based)
|
|
1497
|
-
* @param {number} pageSize - Number of messages per page (default 50)
|
|
1498
|
-
* @param {string} order - 'asc' for oldest first, 'desc' for newest first (default 'asc')
|
|
1499
|
-
* @returns {object} Object with messages array, pagination info
|
|
1500
|
-
*/
|
|
1501
|
-
}, {
|
|
1502
|
-
key: "historyGetPage",
|
|
1503
|
-
value: function historyGetPage() {
|
|
1504
|
-
var page = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
|
|
1505
|
-
var pageSize = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 50;
|
|
1506
|
-
var order = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'asc';
|
|
1507
|
-
var totalMessages = this._history.length;
|
|
1508
|
-
var totalPages = Math.ceil(totalMessages / pageSize);
|
|
1509
|
-
var currentPage = Math.max(1, Math.min(page, totalPages || 1));
|
|
1510
|
-
var start, end;
|
|
1511
|
-
if (order === 'desc') {
|
|
1512
|
-
// For descending order, page 1 shows the newest messages
|
|
1513
|
-
start = Math.max(0, totalMessages - currentPage * pageSize);
|
|
1514
|
-
end = totalMessages - (currentPage - 1) * pageSize;
|
|
1515
|
-
} else {
|
|
1516
|
-
// For ascending order, page 1 shows the oldest messages
|
|
1517
|
-
start = (currentPage - 1) * pageSize;
|
|
1518
|
-
end = Math.min(start + pageSize, totalMessages);
|
|
1519
|
-
}
|
|
1520
|
-
var messages = this._history.slice(start, end);
|
|
1521
|
-
|
|
1522
|
-
// Reverse messages array if descending order requested
|
|
1523
|
-
if (order === 'desc') {
|
|
1524
|
-
messages.reverse();
|
|
1525
|
-
}
|
|
1526
|
-
return {
|
|
1527
|
-
messages: messages,
|
|
1528
|
-
pagination: {
|
|
1529
|
-
currentPage: currentPage,
|
|
1530
|
-
pageSize: pageSize,
|
|
1531
|
-
totalPages: totalPages,
|
|
1532
|
-
totalMessages: totalMessages,
|
|
1533
|
-
hasNext: currentPage < totalPages,
|
|
1534
|
-
hasPrevious: currentPage > 1,
|
|
1535
|
-
order: order
|
|
765
|
+
if (n < 0) {
|
|
766
|
+
return this._history.slice(n);
|
|
1536
767
|
}
|
|
1537
|
-
|
|
1538
|
-
}
|
|
1539
|
-
|
|
1540
|
-
/**
|
|
1541
|
-
* Get information about history size and pagination
|
|
1542
|
-
* @param {number} pageSize - Size to calculate pages for (default 50)
|
|
1543
|
-
* @returns {object} History metadata
|
|
1544
|
-
*/
|
|
1545
|
-
/**
|
|
1546
|
-
* Search history for messages matching criteria
|
|
1547
|
-
* @param {object} criteria - Search criteria object
|
|
1548
|
-
* @param {string} criteria.text - Text to search for in message content
|
|
1549
|
-
* @param {string} criteria.userString - Filter by user name
|
|
1550
|
-
* @param {string} criteria.role - Filter by role
|
|
1551
|
-
* @param {array} criteria.tags - Filter by tags (messages with any of these tags)
|
|
1552
|
-
* @param {number} criteria.limit - Maximum results to return (default 100)
|
|
1553
|
-
* @returns {array} Array of matching messages
|
|
1554
|
-
*/
|
|
1555
|
-
/**
|
|
1556
|
-
* Searches through message history with various filters
|
|
1557
|
-
* @param {Object} [criteria={}] - Search criteria
|
|
1558
|
-
* @param {string} [criteria.text] - Text to search for in message content
|
|
1559
|
-
* @param {string} [criteria.userString] - Filter by specific user
|
|
1560
|
-
* @param {string} [criteria.role] - Filter by role (user, assistant, system)
|
|
1561
|
-
* @param {string[]} [criteria.tags] - Filter by tags (messages must have at least one)
|
|
1562
|
-
* @param {number} [criteria.limit=100] - Maximum number of results
|
|
1563
|
-
* @returns {Array} Array of matching messages
|
|
1564
|
-
* @since 1.1.15
|
|
1565
|
-
* @example
|
|
1566
|
-
* // Search for messages containing 'error'
|
|
1567
|
-
* const errors = chat.historySearch({ text: 'error' });
|
|
1568
|
-
*
|
|
1569
|
-
* // Find all bot messages
|
|
1570
|
-
* const botMessages = chat.historySearch({ role: 'assistant' });
|
|
1571
|
-
*
|
|
1572
|
-
* // Complex search
|
|
1573
|
-
* const results = chat.historySearch({
|
|
1574
|
-
* text: 'help',
|
|
1575
|
-
* userString: 'Support',
|
|
1576
|
-
* tags: ['urgent'],
|
|
1577
|
-
* limit: 20
|
|
1578
|
-
* });
|
|
1579
|
-
*/
|
|
1580
|
-
}, {
|
|
1581
|
-
key: "historySearch",
|
|
1582
|
-
value: function historySearch() {
|
|
1583
|
-
var criteria = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
1584
|
-
var results = this._history;
|
|
1585
|
-
|
|
1586
|
-
// Filter by text content (case-insensitive)
|
|
1587
|
-
if (criteria.text) {
|
|
1588
|
-
var searchText = criteria.text.toLowerCase();
|
|
1589
|
-
results = results.filter(function (msg) {
|
|
1590
|
-
return msg.content.toLowerCase().includes(searchText);
|
|
1591
|
-
});
|
|
768
|
+
return this._history.slice(n, n + 1);
|
|
1592
769
|
}
|
|
1593
|
-
|
|
1594
|
-
// Filter by user
|
|
1595
|
-
if (criteria.userString) {
|
|
1596
|
-
results = results.filter(function (msg) {
|
|
1597
|
-
return msg.userString === criteria.userString;
|
|
1598
|
-
});
|
|
1599
|
-
}
|
|
1600
|
-
|
|
1601
|
-
// Filter by role
|
|
1602
|
-
if (criteria.role) {
|
|
1603
|
-
results = results.filter(function (msg) {
|
|
1604
|
-
return msg.role === criteria.role;
|
|
1605
|
-
});
|
|
1606
|
-
}
|
|
1607
|
-
|
|
1608
|
-
// Filter by tags (match any tag)
|
|
1609
|
-
if (criteria.tags && criteria.tags.length > 0) {
|
|
1610
|
-
results = results.filter(function (msg) {
|
|
1611
|
-
return msg.tags && msg.tags.some(function (tag) {
|
|
1612
|
-
return criteria.tags.includes(tag);
|
|
1613
|
-
});
|
|
1614
|
-
});
|
|
1615
|
-
}
|
|
1616
|
-
|
|
1617
|
-
// Limit results
|
|
1618
|
-
var limit = criteria.limit || 100;
|
|
1619
|
-
if (results.length > limit) {
|
|
1620
|
-
results = results.slice(0, limit);
|
|
1621
|
-
}
|
|
1622
|
-
return results;
|
|
1623
|
-
}
|
|
1624
|
-
|
|
1625
|
-
/**
|
|
1626
|
-
* Gets metadata and statistics about the message history
|
|
1627
|
-
* @param {number} [pageSize=50] - Page size for calculating total pages
|
|
1628
|
-
* @returns {Object} History information object
|
|
1629
|
-
* @returns {number} returns.totalMessages - Total number of messages
|
|
1630
|
-
* @returns {number} returns.totalPages - Total pages based on page size
|
|
1631
|
-
* @returns {Object|null} returns.oldestMessage - First message info
|
|
1632
|
-
* @returns {Object|null} returns.newestMessage - Last message info
|
|
1633
|
-
* @returns {Object} returns.memoryUsage - Memory usage statistics
|
|
1634
|
-
* @since 1.1.15
|
|
1635
|
-
* @example
|
|
1636
|
-
* const info = chat.historyGetInfo();
|
|
1637
|
-
* console.log(`Messages: ${info.totalMessages}`);
|
|
1638
|
-
* console.log(`Memory: ${info.memoryUsage.estimatedSize} bytes`);
|
|
1639
|
-
*/
|
|
1640
|
-
}, {
|
|
1641
|
-
key: "historyGetInfo",
|
|
1642
|
-
value: function historyGetInfo() {
|
|
1643
|
-
var pageSize = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 50;
|
|
1644
|
-
var totalMessages = this._history.length;
|
|
1645
|
-
return {
|
|
1646
|
-
totalMessages: totalMessages,
|
|
1647
|
-
totalPages: Math.ceil(totalMessages / pageSize),
|
|
1648
|
-
oldestMessage: totalMessages > 0 ? {
|
|
1649
|
-
msgid: this._history[0].msgid,
|
|
1650
|
-
timestamp: this._history[0].timestamp,
|
|
1651
|
-
userString: this._history[0].userString
|
|
1652
|
-
} : null,
|
|
1653
|
-
newestMessage: totalMessages > 0 ? {
|
|
1654
|
-
msgid: this._history[totalMessages - 1].msgid,
|
|
1655
|
-
timestamp: this._history[totalMessages - 1].timestamp,
|
|
1656
|
-
userString: this._history[totalMessages - 1].userString
|
|
1657
|
-
} : null,
|
|
1658
|
-
memoryUsage: {
|
|
1659
|
-
estimatedSize: JSON.stringify(this._history).length,
|
|
1660
|
-
averageMessageSize: totalMessages > 0 ? Math.round(JSON.stringify(this._history).length / totalMessages) : 0
|
|
1661
|
-
}
|
|
1662
|
-
};
|
|
770
|
+
return this._history.slice(n, m);
|
|
1663
771
|
}
|
|
1664
|
-
|
|
1665
|
-
/**
|
|
1666
|
-
* Clears all messages and resets the chat
|
|
1667
|
-
* @returns {void}
|
|
1668
|
-
* @example
|
|
1669
|
-
* chat.historyClear(); // Removes all messages
|
|
1670
|
-
*/
|
|
1671
772
|
}, {
|
|
1672
773
|
key: "historyClear",
|
|
1673
774
|
value: function historyClear() {
|
|
1674
775
|
this.msgid = 0;
|
|
1675
|
-
|
|
1676
|
-
// Handle virtual scroller
|
|
1677
|
-
if (this.virtualScroller) {
|
|
1678
|
-
this.virtualScroller.clear();
|
|
1679
|
-
} else {
|
|
1680
|
-
this._messagesArea.innerHTML = "";
|
|
1681
|
-
}
|
|
1682
776
|
this._history = [];
|
|
1683
|
-
this._activeTags.clear();
|
|
1684
777
|
}
|
|
1685
778
|
}, {
|
|
1686
779
|
key: "historyGetLength",
|
|
@@ -1698,29 +791,57 @@ var quikchat = /*#__PURE__*/function () {
|
|
|
1698
791
|
}, {
|
|
1699
792
|
key: "historyGetMessageContent",
|
|
1700
793
|
value: function historyGetMessageContent(n) {
|
|
1701
|
-
if (n >= 0 && n < this._history.length)
|
|
794
|
+
if (n >= 0 && n < this._history.length) {
|
|
795
|
+
return this._history[n].content;
|
|
796
|
+
}
|
|
797
|
+
return "";
|
|
1702
798
|
}
|
|
1703
|
-
|
|
1704
|
-
// expects an array of messages to be in the format of the history object
|
|
1705
799
|
}, {
|
|
1706
|
-
key: "
|
|
1707
|
-
value: function
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
800
|
+
key: "historyExport",
|
|
801
|
+
value: function historyExport() {
|
|
802
|
+
return this._history.map(function (item) {
|
|
803
|
+
return {
|
|
804
|
+
msgid: item.msgid,
|
|
805
|
+
content: item.content,
|
|
806
|
+
userString: item.userString,
|
|
807
|
+
align: item.align,
|
|
808
|
+
role: item.role,
|
|
809
|
+
userID: item.userID,
|
|
810
|
+
visible: item.visible,
|
|
811
|
+
tags: item.tags ? item.tags.slice() : [],
|
|
812
|
+
timestamp: item.timestamp,
|
|
813
|
+
updatedtime: item.updatedtime
|
|
814
|
+
};
|
|
1718
815
|
});
|
|
1719
816
|
}
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
817
|
+
}, {
|
|
818
|
+
key: "historyImport",
|
|
819
|
+
value: function historyImport(data) {
|
|
820
|
+
// Clear existing messages from DOM and history
|
|
821
|
+
this._messagesArea.innerHTML = '';
|
|
822
|
+
this._history = [];
|
|
823
|
+
this.msgid = 0;
|
|
824
|
+
var _iterator2 = _createForOfIteratorHelper(data),
|
|
825
|
+
_step2;
|
|
826
|
+
try {
|
|
827
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
828
|
+
var entry = _step2.value;
|
|
829
|
+
this.messageAddFull({
|
|
830
|
+
content: entry.content || '',
|
|
831
|
+
userString: entry.userString || 'user',
|
|
832
|
+
align: entry.align || 'right',
|
|
833
|
+
role: entry.role || 'user',
|
|
834
|
+
userID: entry.userID,
|
|
835
|
+
visible: entry.visible,
|
|
836
|
+
tags: entry.tags
|
|
837
|
+
});
|
|
838
|
+
}
|
|
839
|
+
} catch (err) {
|
|
840
|
+
_iterator2.e(err);
|
|
841
|
+
} finally {
|
|
842
|
+
_iterator2.f();
|
|
843
|
+
}
|
|
844
|
+
}
|
|
1724
845
|
}, {
|
|
1725
846
|
key: "changeTheme",
|
|
1726
847
|
value: function changeTheme(newTheme) {
|
|
@@ -1728,323 +849,46 @@ var quikchat = /*#__PURE__*/function () {
|
|
|
1728
849
|
this._chatWidget.classList.add(newTheme);
|
|
1729
850
|
this._theme = newTheme;
|
|
1730
851
|
}
|
|
1731
|
-
|
|
1732
|
-
/**
|
|
1733
|
-
* Get the current theme
|
|
1734
|
-
* @returns {string} - The current theme
|
|
1735
|
-
*/
|
|
1736
852
|
}, {
|
|
1737
853
|
key: "theme",
|
|
1738
854
|
get: function get() {
|
|
1739
855
|
return this._theme;
|
|
1740
856
|
}
|
|
1741
|
-
|
|
1742
|
-
/**
|
|
1743
|
-
*
|
|
1744
|
-
* @returns {object} - Returns the version and license information for the library.
|
|
1745
|
-
*/
|
|
1746
|
-
/**
|
|
1747
|
-
* Gets the QuikChat version information
|
|
1748
|
-
* @static
|
|
1749
|
-
* @returns {Object} Version information object
|
|
1750
|
-
* @returns {string} returns.version - Version number (e.g., '1.1.15')
|
|
1751
|
-
* @returns {string} returns.license - License type (e.g., 'BSD-2')
|
|
1752
|
-
* @returns {string} returns.url - Project URL
|
|
1753
|
-
* @returns {boolean} returns.fun - Easter egg flag
|
|
1754
|
-
* @example
|
|
1755
|
-
* const version = quikchat.version();
|
|
1756
|
-
* console.log(`QuikChat v${version.version}`);
|
|
1757
|
-
*/
|
|
1758
|
-
}, {
|
|
1759
|
-
key: "setTagVisibility",
|
|
1760
|
-
value:
|
|
1761
|
-
/**
|
|
1762
|
-
* Sets visibility for all messages with a specific tag
|
|
1763
|
-
* @param {string} tagName - Tag name to control
|
|
1764
|
-
* @param {boolean} isVisible - Whether to show or hide messages with this tag
|
|
1765
|
-
* @returns {boolean} True if successful, false if invalid tag name
|
|
1766
|
-
* @since 1.1.14
|
|
1767
|
-
* @example
|
|
1768
|
-
* // Hide all system messages
|
|
1769
|
-
* chat.setTagVisibility('system', false);
|
|
1770
|
-
*
|
|
1771
|
-
* // Show urgent messages
|
|
1772
|
-
* chat.setTagVisibility('urgent', true);
|
|
1773
|
-
*/
|
|
1774
|
-
function setTagVisibility(tagName, isVisible) {
|
|
1775
|
-
if (typeof tagName !== 'string' || !/^[a-zA-Z0-9-]+$/.test(tagName)) {
|
|
1776
|
-
return false;
|
|
1777
|
-
}
|
|
1778
|
-
var className = "quikchat-show-tag-".concat(tagName);
|
|
1779
|
-
if (isVisible) {
|
|
1780
|
-
this._chatWidget.classList.add(className);
|
|
1781
|
-
} else {
|
|
1782
|
-
this._chatWidget.classList.remove(className);
|
|
1783
|
-
}
|
|
1784
|
-
this._updateMessageStyles();
|
|
1785
|
-
return true;
|
|
1786
|
-
}
|
|
1787
|
-
|
|
1788
|
-
/**
|
|
1789
|
-
* Gets the visibility state of a tag
|
|
1790
|
-
* @param {string} tagName - Tag name to check
|
|
1791
|
-
* @returns {boolean} True if tag is visible, false otherwise
|
|
1792
|
-
* @since 1.1.14
|
|
1793
|
-
* @example
|
|
1794
|
-
* const isVisible = chat.getTagVisibility('system');
|
|
1795
|
-
*/
|
|
1796
|
-
}, {
|
|
1797
|
-
key: "getTagVisibility",
|
|
1798
|
-
value: function getTagVisibility(tagName) {
|
|
1799
|
-
if (typeof tagName !== 'string' || !/^[a-zA-Z0-9-]+$/.test(tagName)) {
|
|
1800
|
-
return false;
|
|
1801
|
-
}
|
|
1802
|
-
return this._chatWidget.classList.contains("quikchat-show-tag-".concat(tagName));
|
|
1803
|
-
}
|
|
1804
|
-
|
|
1805
|
-
/**
|
|
1806
|
-
* Gets all active tags in the chat
|
|
1807
|
-
* @returns {string[]} Array of all tags currently in use
|
|
1808
|
-
* @since 1.1.14
|
|
1809
|
-
* @example
|
|
1810
|
-
* const tags = chat.getActiveTags();
|
|
1811
|
-
* console.log('Active tags:', tags);
|
|
1812
|
-
*/
|
|
1813
|
-
}, {
|
|
1814
|
-
key: "getActiveTags",
|
|
1815
|
-
value: function getActiveTags() {
|
|
1816
|
-
return Array.from(this._activeTags);
|
|
1817
|
-
}
|
|
1818
|
-
|
|
1819
|
-
/**
|
|
1820
|
-
* Checks if virtual scrolling is currently enabled
|
|
1821
|
-
* @returns {boolean} True if virtual scrolling is enabled, false otherwise
|
|
1822
|
-
* @since 1.1.16
|
|
1823
|
-
* @example
|
|
1824
|
-
* if (chat.isVirtualScrollingEnabled()) {
|
|
1825
|
-
* console.log('Virtual scrolling is active');
|
|
1826
|
-
* }
|
|
1827
|
-
*/
|
|
1828
|
-
}, {
|
|
1829
|
-
key: "isVirtualScrollingEnabled",
|
|
1830
|
-
value: function isVirtualScrollingEnabled() {
|
|
1831
|
-
return this.virtualScrollingEnabled && this.virtualScroller !== null;
|
|
1832
|
-
}
|
|
1833
|
-
|
|
1834
|
-
/**
|
|
1835
|
-
* Gets the virtual scrolling configuration
|
|
1836
|
-
* @returns {Object} Virtual scrolling configuration with enabled status and threshold
|
|
1837
|
-
* @since 1.1.16
|
|
1838
|
-
* @example
|
|
1839
|
-
* const config = chat.getVirtualScrollingConfig();
|
|
1840
|
-
* console.log(`Virtual scrolling: ${config.enabled}, threshold: ${config.threshold}`);
|
|
1841
|
-
*/
|
|
1842
|
-
}, {
|
|
1843
|
-
key: "getVirtualScrollingConfig",
|
|
1844
|
-
value: function getVirtualScrollingConfig() {
|
|
1845
|
-
return {
|
|
1846
|
-
enabled: this.virtualScrollingEnabled,
|
|
1847
|
-
active: this.virtualScroller !== null,
|
|
1848
|
-
threshold: this.virtualScrollingThreshold
|
|
1849
|
-
};
|
|
1850
|
-
}
|
|
1851
|
-
|
|
1852
|
-
/**
|
|
1853
|
-
* Set the language for the widget
|
|
1854
|
-
* @param {string} lang - Language code (e.g., 'en', 'es', 'fr')
|
|
1855
|
-
* @param {Object} [translations] - Optional translations object for the language
|
|
1856
|
-
* @example
|
|
1857
|
-
* chat.setLanguage('es', {
|
|
1858
|
-
* sendButton: 'Enviar',
|
|
1859
|
-
* inputPlaceholder: 'Escribe un mensaje...',
|
|
1860
|
-
* titleDefault: 'Chat'
|
|
1861
|
-
* });
|
|
1862
|
-
*/
|
|
1863
|
-
}, {
|
|
1864
|
-
key: "setLanguage",
|
|
1865
|
-
value: function setLanguage(lang, translations) {
|
|
1866
|
-
this.lang = lang;
|
|
1867
|
-
|
|
1868
|
-
// Add translations if provided
|
|
1869
|
-
if (translations) {
|
|
1870
|
-
this.translations[lang] = _objectSpread2(_objectSpread2({}, this.translations[lang]), translations);
|
|
1871
|
-
}
|
|
1872
|
-
|
|
1873
|
-
// Update current translations
|
|
1874
|
-
this.currentTranslations = this.translations[lang] || this.translations['en'];
|
|
1875
|
-
|
|
1876
|
-
// Update UI elements
|
|
1877
|
-
this._updateUITranslations();
|
|
1878
|
-
}
|
|
1879
|
-
|
|
1880
|
-
/**
|
|
1881
|
-
* Get current language
|
|
1882
|
-
* @returns {string} Current language code
|
|
1883
|
-
*/
|
|
1884
|
-
}, {
|
|
1885
|
-
key: "getLanguage",
|
|
1886
|
-
value: function getLanguage() {
|
|
1887
|
-
return this.lang;
|
|
1888
|
-
}
|
|
1889
|
-
|
|
1890
|
-
/**
|
|
1891
|
-
* Set text direction (LTR or RTL)
|
|
1892
|
-
* @param {string} dir - Direction ('ltr' or 'rtl')
|
|
1893
|
-
*/
|
|
1894
|
-
}, {
|
|
1895
|
-
key: "setDirection",
|
|
1896
|
-
value: function setDirection(dir) {
|
|
1897
|
-
if (dir === 'ltr' || dir === 'rtl') {
|
|
1898
|
-
this.dir = dir;
|
|
1899
|
-
this._chatWidget.setAttribute('dir', dir);
|
|
1900
|
-
}
|
|
1901
|
-
}
|
|
1902
|
-
|
|
1903
|
-
/**
|
|
1904
|
-
* Get current text direction
|
|
1905
|
-
* @returns {string} Current direction ('ltr' or 'rtl')
|
|
1906
|
-
*/
|
|
1907
|
-
}, {
|
|
1908
|
-
key: "getDirection",
|
|
1909
|
-
value: function getDirection() {
|
|
1910
|
-
return this.dir;
|
|
1911
|
-
}
|
|
1912
|
-
|
|
1913
|
-
/**
|
|
1914
|
-
* Update UI elements with current translations
|
|
1915
|
-
* @private
|
|
1916
|
-
*/
|
|
1917
|
-
}, {
|
|
1918
|
-
key: "_updateUITranslations",
|
|
1919
|
-
value: function _updateUITranslations() {
|
|
1920
|
-
// Update send button text
|
|
1921
|
-
if (this._sendButton) {
|
|
1922
|
-
this._sendButton.textContent = this.currentTranslations.sendButton || 'Send';
|
|
1923
|
-
}
|
|
1924
|
-
|
|
1925
|
-
// Update input placeholder
|
|
1926
|
-
if (this._textEntry) {
|
|
1927
|
-
this._textEntry.placeholder = this.currentTranslations.inputPlaceholder || 'Type a message...';
|
|
1928
|
-
}
|
|
1929
|
-
|
|
1930
|
-
// Update widget language attribute
|
|
1931
|
-
if (this._chatWidget) {
|
|
1932
|
-
this._chatWidget.setAttribute('lang', this.lang);
|
|
1933
|
-
}
|
|
1934
|
-
}
|
|
1935
|
-
|
|
1936
|
-
/**
|
|
1937
|
-
* Sets the content sanitizer function
|
|
1938
|
-
* @param {Function|null} sanitizer - Function to sanitize content or null to disable
|
|
1939
|
-
* @returns {void}
|
|
1940
|
-
* @example
|
|
1941
|
-
* // Use built-in HTML escaper
|
|
1942
|
-
* chat.setSanitizer(quikchat.sanitizers.escapeHTML);
|
|
1943
|
-
*
|
|
1944
|
-
* // Use custom sanitizer (e.g., DOMPurify)
|
|
1945
|
-
* chat.setSanitizer((content) => DOMPurify.sanitize(content));
|
|
1946
|
-
*
|
|
1947
|
-
* // Disable sanitization
|
|
1948
|
-
* chat.setSanitizer(null);
|
|
1949
|
-
*/
|
|
1950
|
-
}, {
|
|
1951
|
-
key: "setSanitizer",
|
|
1952
|
-
value: function setSanitizer(sanitizer) {
|
|
1953
|
-
if (sanitizer === null || typeof sanitizer === 'function') {
|
|
1954
|
-
this._sanitizer = sanitizer;
|
|
1955
|
-
} else {
|
|
1956
|
-
console.warn('Sanitizer must be a function or null');
|
|
1957
|
-
}
|
|
1958
|
-
}
|
|
1959
|
-
|
|
1960
|
-
/**
|
|
1961
|
-
* Gets the current content sanitizer function
|
|
1962
|
-
* @returns {Function|null} The current sanitizer function or null
|
|
1963
|
-
* @example
|
|
1964
|
-
* const sanitizer = chat.getSanitizer();
|
|
1965
|
-
* if (sanitizer) {
|
|
1966
|
-
* console.log('Sanitization is enabled');
|
|
1967
|
-
* }
|
|
1968
|
-
*/
|
|
1969
|
-
}, {
|
|
1970
|
-
key: "getSanitizer",
|
|
1971
|
-
value: function getSanitizer() {
|
|
1972
|
-
return this._sanitizer;
|
|
1973
|
-
}
|
|
1974
|
-
|
|
1975
|
-
/**
|
|
1976
|
-
* Internal method to apply sanitizer to content
|
|
1977
|
-
* @private
|
|
1978
|
-
* @param {string} content - Content to sanitize
|
|
1979
|
-
* @returns {string} Sanitized content
|
|
1980
|
-
*/
|
|
1981
|
-
}, {
|
|
1982
|
-
key: "_sanitizeContent",
|
|
1983
|
-
value: function _sanitizeContent(content) {
|
|
1984
|
-
if (this._sanitizer && typeof this._sanitizer === 'function') {
|
|
1985
|
-
return this._sanitizer(content);
|
|
1986
|
-
}
|
|
1987
|
-
return content;
|
|
1988
|
-
}
|
|
1989
857
|
}], [{
|
|
1990
858
|
key: "version",
|
|
1991
859
|
value: function version() {
|
|
1992
|
-
return
|
|
860
|
+
return {
|
|
861
|
+
"version": "1.2.4",
|
|
862
|
+
"license": "BSD-2",
|
|
863
|
+
"url": "https://github/deftio/quikchat"
|
|
864
|
+
};
|
|
1993
865
|
}
|
|
1994
866
|
|
|
1995
|
-
/**
|
|
1996
|
-
* Built-in content sanitizers for XSS protection
|
|
1997
|
-
* @static
|
|
1998
|
-
* @type {Object}
|
|
1999
|
-
* @property {Function} escapeHTML - Escapes HTML entities
|
|
2000
|
-
* @property {Function} stripHTML - Removes all HTML tags
|
|
2001
|
-
* @example
|
|
2002
|
-
* // Use built-in HTML escaper
|
|
2003
|
-
* const chat = new quikchat('#chat', onSend, {
|
|
2004
|
-
* sanitizer: quikchat.sanitizers.escapeHTML
|
|
2005
|
-
* });
|
|
2006
|
-
*/
|
|
2007
|
-
}, {
|
|
2008
|
-
key: "loremIpsum",
|
|
2009
|
-
value:
|
|
2010
867
|
/**
|
|
2011
868
|
* quikchat.loremIpsum() - Generate a simple string of Lorem Ipsum text (sample typographer's text) of numChars in length.
|
|
2012
869
|
* borrowed from github.com/deftio/bitwrench.js
|
|
2013
|
-
* @param {number} numChars - The number of characters to generate (random btw 25 and 150 if undefined).
|
|
870
|
+
* @param {number} numChars - The number of characters to generate (random btw 25 and 150 if undefined).
|
|
2014
871
|
* @param {number} [startSpot=0] - The starting index in the Lorem Ipsum text. If undefined, a random startSpot will be generated.
|
|
2015
872
|
* @param {boolean} [startWithCapitalLetter=true] - If true, capitalize the first character or inject a capital letter if the first character isn't a capital letter.
|
|
2016
|
-
*
|
|
873
|
+
*
|
|
2017
874
|
* @returns {string} A string of Lorem Ipsum text.
|
|
2018
|
-
*
|
|
2019
|
-
* @example
|
|
875
|
+
*
|
|
876
|
+
* @example
|
|
2020
877
|
* // Returns 200 characters of Lorem Ipsum starting from index 50
|
|
2021
878
|
* loremIpsum(200, 50);
|
|
2022
|
-
*
|
|
2023
|
-
* @example
|
|
879
|
+
*
|
|
880
|
+
* @example
|
|
2024
881
|
* //Returns a 200 Lorem Ipsum characters starting from a random index
|
|
2025
882
|
* loremIpsum(200);
|
|
2026
883
|
*/
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
* @static
|
|
2031
|
-
* @param {number} [numChars] - Length of text to generate (random if not specified)
|
|
2032
|
-
* @param {number} [startSpot] - Starting offset in Lorem text (random if not specified)
|
|
2033
|
-
* @param {boolean} [startWithCapitalLetter=true] - Whether to capitalize first letter
|
|
2034
|
-
* @returns {string} Generated Lorem Ipsum text
|
|
2035
|
-
* @example
|
|
2036
|
-
* // Generate 100 characters
|
|
2037
|
-
* const text = quikchat.loremIpsum(100);
|
|
2038
|
-
*
|
|
2039
|
-
* // Generate random length
|
|
2040
|
-
* const randomText = quikchat.loremIpsum();
|
|
2041
|
-
*/
|
|
2042
|
-
function loremIpsum(numChars) {
|
|
884
|
+
}, {
|
|
885
|
+
key: "loremIpsum",
|
|
886
|
+
value: function loremIpsum(numChars) {
|
|
2043
887
|
var startSpot = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
|
|
2044
888
|
var startWithCapitalLetter = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
|
2045
889
|
var loremText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. ";
|
|
2046
890
|
if (typeof numChars !== "number") {
|
|
2047
|
-
numChars = Math.floor(Math.random() *
|
|
891
|
+
numChars = Math.floor(Math.random() * 126) + 25;
|
|
2048
892
|
}
|
|
2049
893
|
if (startSpot === undefined) {
|
|
2050
894
|
startSpot = Math.floor(Math.random() * loremText.length);
|
|
@@ -2056,9 +900,6 @@ var quikchat = /*#__PURE__*/function () {
|
|
|
2056
900
|
startSpot = (startSpot + 1) % loremText.length;
|
|
2057
901
|
}
|
|
2058
902
|
var l = loremText.substring(startSpot) + loremText.substring(0, startSpot);
|
|
2059
|
-
if (typeof numChars !== "number") {
|
|
2060
|
-
numChars = l.length;
|
|
2061
|
-
}
|
|
2062
903
|
var s = "";
|
|
2063
904
|
while (numChars > 0) {
|
|
2064
905
|
s += numChars < l.length ? l.substring(0, numChars) : l;
|
|
@@ -2068,128 +909,12 @@ var quikchat = /*#__PURE__*/function () {
|
|
|
2068
909
|
s = s.substring(0, s.length - 1) + "."; // always end on non-whitespace. "." was chosen arbitrarily.
|
|
2069
910
|
}
|
|
2070
911
|
if (startWithCapitalLetter) {
|
|
2071
|
-
|
|
2072
|
-
c = /[A-Z]/.test(c) ? c : "M";
|
|
2073
|
-
s = c + s.substring(1);
|
|
912
|
+
s = s[0].toUpperCase() + s.substring(1);
|
|
2074
913
|
}
|
|
2075
914
|
return s;
|
|
2076
915
|
}
|
|
2077
|
-
}, {
|
|
2078
|
-
key: "tempMessageGenerator",
|
|
2079
|
-
value:
|
|
2080
|
-
/**
|
|
2081
|
-
* Creates a temporary message that updates periodically
|
|
2082
|
-
* @static
|
|
2083
|
-
* @param {string|HTMLElement} domElement - Element selector or DOM element
|
|
2084
|
-
* @param {string} content - Initial message content
|
|
2085
|
-
* @param {number} interval - Update interval in milliseconds (min 100ms)
|
|
2086
|
-
* @param {Function} [cb=null] - Callback to generate new content
|
|
2087
|
-
* @param {string} cb.message - Current message
|
|
2088
|
-
* @param {number} cb.count - Update count
|
|
2089
|
-
* @returns {void}
|
|
2090
|
-
* @example
|
|
2091
|
-
* // Simple loading indicator
|
|
2092
|
-
* quikchat.tempMessageGenerator('#loading', 'Loading', 500);
|
|
2093
|
-
*
|
|
2094
|
-
* // Custom update function
|
|
2095
|
-
* quikchat.tempMessageGenerator('#status', 'Processing', 1000, (msg, count) => {
|
|
2096
|
-
* return `Processing... ${count}%`;
|
|
2097
|
-
* });
|
|
2098
|
-
*/
|
|
2099
|
-
function tempMessageGenerator(domElement, content, interval) {
|
|
2100
|
-
var cb = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
|
|
2101
|
-
interval = Math.max(interval, 100); // Ensure at least 100ms interval
|
|
2102
|
-
|
|
2103
|
-
var count = 0;
|
|
2104
|
-
var defaultCB = function defaultCB(msg, count) {
|
|
2105
|
-
msg += ".";
|
|
2106
|
-
return msg;
|
|
2107
|
-
};
|
|
2108
|
-
if (cb && typeof cb !== 'function') {
|
|
2109
|
-
cb = null;
|
|
2110
|
-
}
|
|
2111
|
-
cb = cb || defaultCB;
|
|
2112
|
-
|
|
2113
|
-
// if its a string, then get the element (css sel) or its an DOM element already
|
|
2114
|
-
var el = domElement;
|
|
2115
|
-
if (typeof el === 'string') {
|
|
2116
|
-
el = document.querySelector(el);
|
|
2117
|
-
}
|
|
2118
|
-
var element = el;
|
|
2119
|
-
|
|
2120
|
-
// Ensure the element exists
|
|
2121
|
-
if (!element) return;
|
|
2122
|
-
element.innerHTML = content;
|
|
2123
|
-
var currentMsg = content;
|
|
2124
|
-
var intervalId = setInterval(function () {
|
|
2125
|
-
if (element.innerHTML !== currentMsg) {
|
|
2126
|
-
clearInterval(intervalId); // Stop updating if content is changed externally
|
|
2127
|
-
return;
|
|
2128
|
-
}
|
|
2129
|
-
currentMsg = String(cb(currentMsg, count)); // Use callback return value if provided
|
|
2130
|
-
|
|
2131
|
-
count++;
|
|
2132
|
-
element.innerHTML = currentMsg;
|
|
2133
|
-
}, interval);
|
|
2134
|
-
}
|
|
2135
|
-
}, {
|
|
2136
|
-
key: "createTempMessageDOMStr",
|
|
2137
|
-
value: function createTempMessageDOMStr(initialContent) {
|
|
2138
|
-
var updateInterval = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1000;
|
|
2139
|
-
var callback = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
|
|
2140
|
-
var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
2141
|
-
// Make sure the interval is at least 100ms
|
|
2142
|
-
updateInterval = Math.max(updateInterval, 100);
|
|
2143
|
-
|
|
2144
|
-
// Validate callback; if not a function, ignore it.
|
|
2145
|
-
if (callback && typeof callback !== 'function') {
|
|
2146
|
-
callback = null;
|
|
2147
|
-
}
|
|
2148
|
-
// Default callback simply appends a dot.
|
|
2149
|
-
callback = callback || function (msg, count) {
|
|
2150
|
-
return msg + ".";
|
|
2151
|
-
};
|
|
2152
|
-
|
|
2153
|
-
// Allow an optional CSS class for the container element
|
|
2154
|
-
var containerClass = options.containerClass ? options.containerClass : '';
|
|
2155
|
-
|
|
2156
|
-
// Generate a unique id so that the inline script can reliably find the container.
|
|
2157
|
-
var uniqueId = "tempMsg_" + Date.now() + "_" + Math.floor(Math.random() * 1000000);
|
|
2158
|
-
|
|
2159
|
-
// Build and return the HTML string.
|
|
2160
|
-
// Note the use of <\/script> (with a backslash) so that the inline script is not terminated early.
|
|
2161
|
-
return "\n <span id=\"".concat(uniqueId, "\" ").concat(containerClass ? "class=\"".concat(containerClass, "\"") : '', ">\n ").concat(initialContent, "\n </span>\n <script>\n (function(){\n // Get our container element by its unique id.\n var container = document.getElementById(\"").concat(uniqueId, "\");\n if (!container) return;\n var count = 0;\n var currentMsg = container.innerHTML;\n var interval = ").concat(updateInterval, ";\n // Convert the callback function into its string representation.\n var cb = ").concat(callback.toString(), ";\n var intervalId = setInterval(function(){\n // If the content has been replaced, stop updating.\n if(container.innerHTML !== currentMsg){\n clearInterval(intervalId);\n return;\n }\n // Use the callback to generate the new message.\n currentMsg = String(cb(currentMsg, count));\n count++;\n container.innerHTML = currentMsg;\n }, interval);\n })();\n </script>\n ");
|
|
2162
|
-
}
|
|
2163
916
|
}]);
|
|
2164
917
|
}();
|
|
2165
|
-
_defineProperty(quikchat, "sanitizers", {
|
|
2166
|
-
/**
|
|
2167
|
-
* Escapes HTML entities to prevent XSS
|
|
2168
|
-
* @param {string} str - String to escape
|
|
2169
|
-
* @returns {string} Escaped string
|
|
2170
|
-
*/
|
|
2171
|
-
escapeHTML: function escapeHTML(str) {
|
|
2172
|
-
if (typeof str !== 'string') return str;
|
|
2173
|
-
return str.replace(/[&<>"']/g, function (m) {
|
|
2174
|
-
return {
|
|
2175
|
-
'&': '&',
|
|
2176
|
-
'<': '<',
|
|
2177
|
-
'>': '>',
|
|
2178
|
-
'"': '"',
|
|
2179
|
-
"'": '''
|
|
2180
|
-
}[m];
|
|
2181
|
-
});
|
|
2182
|
-
},
|
|
2183
|
-
/**
|
|
2184
|
-
* Strips all HTML tags but keeps text content
|
|
2185
|
-
* @param {string} str - String to strip
|
|
2186
|
-
* @returns {string} Text without HTML tags
|
|
2187
|
-
*/
|
|
2188
|
-
stripHTML: function stripHTML(str) {
|
|
2189
|
-
if (typeof str !== 'string') return str;
|
|
2190
|
-
return str.replace(/<[^>]*>/g, '');
|
|
2191
|
-
}
|
|
2192
|
-
});
|
|
2193
918
|
|
|
2194
919
|
module.exports = quikchat;
|
|
2195
920
|
//# sourceMappingURL=quikchat.cjs.js.map
|