@paramms/chat-widget 1.0.37 → 1.0.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chatlist.js +115 -92
- package/dist/chatlist.js.map +1 -1
- package/dist/core.js.map +1 -1
- package/dist/embed.d.ts +4 -0
- package/dist/embed.js +33 -15
- package/dist/embed.js.map +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.js +586 -468
- package/dist/index.js.map +1 -1
- package/dist/outbox.js +10 -9
- package/dist/outbox.js.map +1 -1
- package/dist/protocol/frames.d.ts +4 -0
- package/dist/react.d.ts +10 -3
- package/dist/react.js +310 -287
- package/dist/react.js.map +1 -1
- package/dist/renderer.d.ts +9 -7
- package/dist/store.d.ts +4 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var y = (
|
|
4
|
-
import { p as
|
|
5
|
-
import { h as
|
|
6
|
-
import { P as
|
|
7
|
-
import { e as
|
|
8
|
-
import { E2ESession as
|
|
9
|
-
const
|
|
10
|
-
class
|
|
1
|
+
var Pe = Object.defineProperty;
|
|
2
|
+
var Le = (t, e, i) => e in t ? Pe(t, e, { enumerable: !0, configurable: !0, writable: !0, value: i }) : t[e] = i;
|
|
3
|
+
var y = (t, e, i) => Le(t, typeof e != "symbol" ? e + "" : e, i);
|
|
4
|
+
import { p as je, r as Ae, a as $e } from "./codec.js";
|
|
5
|
+
import { h as st } from "./codec.js";
|
|
6
|
+
import { P as Be, C as Me, b as Re } from "./outbox.js";
|
|
7
|
+
import { e as at } from "./outbox.js";
|
|
8
|
+
import { E2ESession as qe, extractX3DHInit as Oe } from "./e2e.js";
|
|
9
|
+
const xe = "http://www.w3.org/2000/svg", De = 8e3;
|
|
10
|
+
class He {
|
|
11
11
|
constructor() {
|
|
12
12
|
y(this, "svg", null);
|
|
13
13
|
y(this, "timers", /* @__PURE__ */ new Set());
|
|
@@ -23,7 +23,7 @@ class ke {
|
|
|
23
23
|
ensureSvg() {
|
|
24
24
|
var i;
|
|
25
25
|
if ((i = this.svg) != null && i.isConnected) return this.svg;
|
|
26
|
-
const e = document.createElementNS(
|
|
26
|
+
const e = document.createElementNS(xe, "svg");
|
|
27
27
|
return e.setAttribute("data-relay-annotations", ""), e.setAttribute("aria-hidden", "true"), e.setAttribute(
|
|
28
28
|
"style",
|
|
29
29
|
"position:fixed;inset:0;width:100vw;height:100vh;pointer-events:none;z-index:2147483000;"
|
|
@@ -32,15 +32,15 @@ class ke {
|
|
|
32
32
|
draw(e) {
|
|
33
33
|
var b;
|
|
34
34
|
if (typeof document > "u" || !((b = e.points) != null && b.length)) return;
|
|
35
|
-
const i = this.ensureSvg(), s = window.innerWidth,
|
|
36
|
-
|
|
35
|
+
const i = this.ensureSvg(), s = window.innerWidth, r = window.innerHeight, a = document.createElementNS(xe, "polyline");
|
|
36
|
+
a.setAttribute("points", e.points.map((d) => `${(d.x * s).toFixed(1)},${(d.y * r).toFixed(1)}`).join(" ")), a.setAttribute("fill", "none"), a.setAttribute("stroke", e.color || "#ff3b30"), a.setAttribute("stroke-width", String(e.width || 3)), a.setAttribute("stroke-linecap", "round"), a.setAttribute("stroke-linejoin", "round"), a.setAttribute("data-stroke-id", e.id), i.append(a);
|
|
37
37
|
const f = setTimeout(() => {
|
|
38
|
-
|
|
38
|
+
a.style.transition = "opacity 600ms", a.style.opacity = "0";
|
|
39
39
|
const d = setTimeout(() => {
|
|
40
|
-
|
|
40
|
+
a.remove(), this.timers.delete(d);
|
|
41
41
|
}, 650);
|
|
42
42
|
this.timers.add(d), this.timers.delete(f);
|
|
43
|
-
},
|
|
43
|
+
}, De);
|
|
44
44
|
this.timers.add(f);
|
|
45
45
|
}
|
|
46
46
|
clear() {
|
|
@@ -53,19 +53,29 @@ class ke {
|
|
|
53
53
|
this.timers.clear(), (e = this.svg) == null || e.remove(), this.svg = null;
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
|
-
const
|
|
56
|
+
const me = "objectchat-widget-styles", Ne = ["👍", "❤️", "😂", "😮", "😢", "🙏"], _e = 400, Fe = '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M22 2 11 13M22 2l-7 20-4-9-9-4 20-7z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>', Ue = `
|
|
57
57
|
.ocw { --ocw-accent:#4F63F5; --ocw-bg:#f3efe9; --ocw-card:#fff; --ocw-line:#ececec; --ocw-ink:#1c1b1a; --ocw-mut:#9b9690;
|
|
58
58
|
position:relative;
|
|
59
59
|
display:flex; flex-direction:column; height:100%; min-height:320px; background:var(--ocw-bg);
|
|
60
60
|
font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',system-ui,sans-serif; color:var(--ocw-ink); overflow:hidden; }
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
61
|
+
/* ── Responsive sizing ──────────────────────────────────────────────────────
|
|
62
|
+
* Sizing is driven by the WIDGET'S OWN width (ResizeObserver toggles
|
|
63
|
+
* .ocw-compact below 400px), not the viewport — so a widget embedded in a
|
|
64
|
+
* narrow desktop sidebar sizes the same as one on a phone, and a tablet in
|
|
65
|
+
* landscape keeps comfortable desktop sizing. A viewport query alone can't
|
|
66
|
+
* see the container. Fullscreen (launcher on mobile) additionally gets
|
|
67
|
+
* .ocw-fs from the launcher, which is the only case that should remove the
|
|
68
|
+
* corner radius — an INLINE embed on a phone must NOT take over the page
|
|
69
|
+
* (the old blanket min-height:100dvh rule did exactly that). */
|
|
70
|
+
.ocw.ocw-fs { border-radius:0 !important; }
|
|
71
|
+
.ocw-compact .ocw-bubble { font-size:15px; }
|
|
72
|
+
.ocw-compact.ocw .ocw-input textarea { font-size:16px; } /* ≥16px prevents iOS zoom on focus */
|
|
73
|
+
.ocw-compact .ocw-chip { padding:9px 14px; font-size:14px; }
|
|
74
|
+
.ocw-compact .ocw-modal-card { width:90%; }
|
|
75
|
+
.ocw-compact .ocw-row { max-width:94%; }
|
|
76
|
+
.ocw-compact .ocw-sendbtn { min-width:44px; height:44px; }
|
|
77
|
+
.ocw-compact .ocw-back { width:34px; height:34px; }
|
|
78
|
+
.ocw-compact .ocw-quick button { padding:9px 15px; font-size:14px; }
|
|
69
79
|
/* RTL support: when the host element has dir=rtl, flip layout direction */
|
|
70
80
|
[dir="rtl"] .ocw-row.mine { flex-direction:row; }
|
|
71
81
|
[dir="rtl"] .ocw-row.theirs { flex-direction:row-reverse; }
|
|
@@ -114,7 +124,6 @@ const oe = "objectchat-widget-styles", Ce = ["👍", "❤️", "😂", "😮", "
|
|
|
114
124
|
.ocw-react-pill { display:inline-flex; align-items:center; gap:3px; border:1px solid #e3ded7; border-radius:999px; padding:2px 7px; background:#fff; font-size:12px; cursor:pointer; }
|
|
115
125
|
.ocw-react-pill:hover { border-color:var(--ocw-accent); }
|
|
116
126
|
.ocw-react-pill.mine { border-color:var(--ocw-accent); background:#fff8f5; }
|
|
117
|
-
.ocw-react-add { display:none; position:absolute; bottom:100%; left:0; margin-bottom:4px; background:#fff; border:1px solid #e3ded7; border-radius:14px; padding:6px 8px; box-shadow:0 4px 16px rgba(0,0,0,.12); display:flex; gap:4px; z-index:10; }
|
|
118
127
|
.ocw-react-wrap { position:relative; }
|
|
119
128
|
.ocw-react-wrap:not(:hover) .ocw-react-picker { display:none; }
|
|
120
129
|
.ocw-react-picker { position:absolute; bottom:calc(100% + 4px); left:0; background:#fff; border:1px solid #e3ded7; border-radius:14px; padding:6px 8px; box-shadow:0 4px 16px rgba(0,0,0,.12); display:flex; gap:4px; z-index:10; white-space:nowrap; }
|
|
@@ -203,10 +212,19 @@ const oe = "objectchat-widget-styles", Ce = ["👍", "❤️", "😂", "😮", "
|
|
|
203
212
|
.ocw-footer a:hover { color:var(--ocw-accent); }
|
|
204
213
|
.ocw-attach { background:none;border:none;cursor:pointer;font-size:18px;padding:4px 6px;opacity:.6;flex-none; }
|
|
205
214
|
.ocw-attach:hover { opacity:1; }
|
|
206
|
-
.ocw-input textarea { flex:1; resize:none; border:1px solid #e3ded7; border-radius:22px; padding:11px 16px; font:inherit; font-size:14px; background:#fff; outline:none; max-height:
|
|
215
|
+
.ocw-input textarea { flex:1; min-width:0; resize:none; border:1px solid #e3ded7; border-radius:22px; padding:11px 16px; font:inherit; font-size:14px; line-height:1.4; background:#fff; outline:none; max-height:120px; overflow-y:auto; }
|
|
207
216
|
.ocw-input textarea:focus { border-color:var(--ocw-accent); }
|
|
208
|
-
|
|
217
|
+
/* Send button auto-sizes to its label: the default is a fixed circle around an
|
|
218
|
+
* inline SVG; a TEXT label (i18n.send: "Send", "보내기", "Enviar"…) switches to
|
|
219
|
+
* .ocw-sendbtn-label — a pill whose width follows the text. A fixed 42px
|
|
220
|
+
* circle with 18px type overflowed the moment anyone localized the label. */
|
|
221
|
+
.ocw-sendbtn { min-width:42px; height:42px; border-radius:999px; border:none; background:var(--ocw-accent); color:#fff; font:inherit; font-size:14px; font-weight:600; cursor:pointer; flex:none; display:flex; align-items:center; justify-content:center; padding:0; transition:opacity .15s, transform .1s; }
|
|
222
|
+
.ocw-sendbtn-label { padding:0 16px; white-space:nowrap; }
|
|
223
|
+
.ocw-sendbtn svg { width:19px; height:19px; display:block; }
|
|
224
|
+
.ocw-sendbtn:not(:disabled):hover { transform:scale(1.05); }
|
|
225
|
+
.ocw-sendbtn:not(:disabled):active { transform:scale(.96); }
|
|
209
226
|
.ocw-sendbtn:disabled { opacity:.5; cursor:default; }
|
|
227
|
+
.ocw-sendbtn:focus-visible, .ocw-back:focus-visible, .ocw-chip:focus-visible { outline:2px solid var(--ocw-accent); outline-offset:2px; }
|
|
210
228
|
.ocw-cobrowse-btn { display:none; }
|
|
211
229
|
.ocw-cobrowse-btn.show { display:inline-flex; }
|
|
212
230
|
.ocw-cobrowse-btn.on { color:var(--ocw-accent); border-color:var(--ocw-accent); }
|
|
@@ -226,42 +244,42 @@ const oe = "objectchat-widget-styles", Ce = ["👍", "❤️", "😂", "😮", "
|
|
|
226
244
|
.ocw-bubble-wrap:hover .ocw-translate-btn { opacity:1; }
|
|
227
245
|
.ocw-translated-tag { font-size:10px; color:var(--ocw-mut); margin-top:2px; }
|
|
228
246
|
`;
|
|
229
|
-
function
|
|
230
|
-
if (typeof document > "u" || document.getElementById(
|
|
231
|
-
const
|
|
232
|
-
|
|
247
|
+
function We() {
|
|
248
|
+
if (typeof document > "u" || document.getElementById(me)) return;
|
|
249
|
+
const t = document.createElement("style");
|
|
250
|
+
t.id = me, t.textContent = Ue, document.head.appendChild(t);
|
|
233
251
|
}
|
|
234
|
-
function t
|
|
235
|
-
const s = document.createElement(
|
|
252
|
+
function o(t, e, i) {
|
|
253
|
+
const s = document.createElement(t);
|
|
236
254
|
return e && (s.className = e), i !== void 0 && (s.textContent = i), s;
|
|
237
255
|
}
|
|
238
|
-
function
|
|
256
|
+
function Ve(t) {
|
|
239
257
|
try {
|
|
240
|
-
return new Date(
|
|
258
|
+
return new Date(t).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
|
241
259
|
} catch {
|
|
242
260
|
return "";
|
|
243
261
|
}
|
|
244
262
|
}
|
|
245
|
-
function
|
|
263
|
+
function ie(t) {
|
|
246
264
|
var e;
|
|
247
|
-
switch (
|
|
265
|
+
switch (t.kind) {
|
|
248
266
|
case "text":
|
|
249
|
-
return
|
|
267
|
+
return t.text;
|
|
250
268
|
case "system":
|
|
251
|
-
return typeof ((e =
|
|
269
|
+
return typeof ((e = t.data) == null ? void 0 : e.message) == "string" ? String(t.data.message) : t.event;
|
|
252
270
|
case "card":
|
|
253
|
-
return [
|
|
271
|
+
return [t.title, t.body].filter(Boolean).join(" — ");
|
|
254
272
|
case "attachment":
|
|
255
|
-
return
|
|
273
|
+
return t.name ?? t.url;
|
|
256
274
|
case "form":
|
|
257
|
-
return
|
|
275
|
+
return t.prompt;
|
|
258
276
|
case "appointment":
|
|
259
|
-
return `📅 ${
|
|
277
|
+
return `📅 ${t.title} — ${new Date(t.startIso).toLocaleString()}`;
|
|
260
278
|
}
|
|
261
279
|
}
|
|
262
|
-
class
|
|
280
|
+
class Ye {
|
|
263
281
|
/** Last seq the guest has seen per conversationId — used to compute unread badges. */
|
|
264
|
-
constructor(e, i, s,
|
|
282
|
+
constructor(e, i, s, r = {}) {
|
|
265
283
|
y(this, "scroll");
|
|
266
284
|
y(this, "chips");
|
|
267
285
|
y(this, "typing");
|
|
@@ -282,6 +300,9 @@ class Ee {
|
|
|
282
300
|
y(this, "connStatus");
|
|
283
301
|
y(this, "typingTimer", null);
|
|
284
302
|
y(this, "csatSubmitted", !1);
|
|
303
|
+
y(this, "sendBtn");
|
|
304
|
+
/** Container-driven responsive sizing — toggles .ocw-compact (see CSS note). */
|
|
305
|
+
y(this, "compactObserver", null);
|
|
285
306
|
// ── Co-browsing (shared whiteboard) ─────────────────────────────────────
|
|
286
307
|
y(this, "cobrowseBtn");
|
|
287
308
|
y(this, "cobrowseCanvas");
|
|
@@ -295,65 +316,77 @@ class Ee {
|
|
|
295
316
|
// ── Live translation ──────────────────────────────────────────────────-
|
|
296
317
|
y(this, "translationCache", /* @__PURE__ */ new Map());
|
|
297
318
|
y(this, "showingTranslation", /* @__PURE__ */ new Set());
|
|
319
|
+
/** Whether the subject card (server Subject entity, mount config fallback)
|
|
320
|
+
* has been built — built once when data first arrives. */
|
|
298
321
|
y(this, "subjectBuilt", !1);
|
|
299
|
-
var
|
|
300
|
-
this.root = e, this.me = i, this.h = s, this.cfg =
|
|
301
|
-
const
|
|
322
|
+
var k, I, j, C, R, A, O, U, T, B;
|
|
323
|
+
this.root = e, this.me = i, this.h = s, this.cfg = r, We(), e.replaceChildren(), e.classList.add("ocw"), r.accent && e.style.setProperty("--ocw-accent", r.accent);
|
|
324
|
+
const a = o("div", "ocw-head");
|
|
302
325
|
if (this.h.onBack) {
|
|
303
|
-
const
|
|
304
|
-
|
|
326
|
+
const m = o("button", "ocw-back", "‹");
|
|
327
|
+
m.type = "button", m.setAttribute("aria-label", "Back"), m.addEventListener("click", () => this.h.onBack()), a.append(m);
|
|
305
328
|
}
|
|
306
|
-
const f =
|
|
307
|
-
if ((
|
|
308
|
-
const
|
|
309
|
-
|
|
329
|
+
const f = o("div", "ocw-avatar");
|
|
330
|
+
if ((k = r.userInfo) != null && k.avatar) {
|
|
331
|
+
const m = document.createElement("img");
|
|
332
|
+
m.src = r.userInfo.avatar, m.alt = r.userInfo.name ?? "You", m.style.cssText = "width:100%;height:100%;border-radius:50%;object-fit:cover", f.append(m);
|
|
310
333
|
} else
|
|
311
|
-
f.textContent = (
|
|
312
|
-
|
|
313
|
-
const b =
|
|
314
|
-
this.headerName =
|
|
334
|
+
f.textContent = (I = r.userInfo) != null && I.name ? r.userInfo.name[0].toUpperCase() : "🧑";
|
|
335
|
+
a.append(f);
|
|
336
|
+
const b = o("div", "ocw-head-main");
|
|
337
|
+
this.headerName = o("div", "ocw-head-name", ((j = r.subject) == null ? void 0 : j.ownerLabel) ?? ((C = r.subject) == null ? void 0 : C.title) ?? ""), b.append(this.headerName), (R = r.subject) != null && R.subtitle && b.append(o("div", "ocw-head-meta", r.subject.subtitle)), a.append(b), this.statusBadge = o("span", "ocw-badge", ((A = r.subject) == null ? void 0 : A.status) ?? ""), (O = r.subject) != null && O.status || (this.statusBadge.style.display = "none"), a.append(this.statusBadge), this.e2eBadge = o("span", "ocw-e2e", "🔒 E2E"), this.e2eBadge.style.display = "none", a.append(this.e2eBadge), this.connStatus = o("span", "ocw-conn-status"), this.connStatus.style.display = "none", a.append(this.connStatus), this.cobrowseBtn = o("button", "ocw-menu ocw-cobrowse-btn", "🖍"), this.cobrowseBtn.title = "Shared whiteboard — draw to point things out together", this.cobrowseBtn.addEventListener("click", () => {
|
|
315
338
|
this.cobrowseActive = !this.cobrowseActive, this.updateCobrowseUI();
|
|
316
|
-
}),
|
|
317
|
-
const d =
|
|
318
|
-
d.append(
|
|
319
|
-
for (const
|
|
320
|
-
const S =
|
|
339
|
+
}), a.append(this.cobrowseBtn), a.append(o("button", "ocw-menu", "⋯")), this.chips = o("div", "ocw-chiprow"), this.scroll = o("div", "ocw-scroll"), this.subjectCard = o("div", "ocw-subject"), this.typing = o("div", "ocw-typing");
|
|
340
|
+
const d = o("div", "ocw-typing-bubble");
|
|
341
|
+
d.append(o("div", "ocw-typing-dot"), o("div", "ocw-typing-dot"), o("div", "ocw-typing-dot")), this.typing.append(o("div", "ocw-dot", "🧑"), d), this.quick = o("div", "ocw-quick");
|
|
342
|
+
for (const m of r.quickReplies ?? []) {
|
|
343
|
+
const S = o("button", void 0, m);
|
|
321
344
|
S.addEventListener("click", () => {
|
|
322
|
-
this.h.onSend(
|
|
345
|
+
this.h.onSend(m), this.quick.style.display = "none";
|
|
323
346
|
}), this.quick.append(S);
|
|
324
347
|
}
|
|
325
|
-
this.formHost =
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
348
|
+
this.formHost = o("div", "ocw-form-host"), this.csatPanel = o("div", "ocw-csat"), this.csatPanel.style.display = "none", this.offlinePanel = o("div", "ocw-offline"), this.offlinePanel.style.display = "none", this.preChatPanel = o("div", "ocw-prechat"), this.preChatPanel.style.display = "none", this.deflectPanel = o("div", "ocw-deflect"), this.deflectPanel.style.display = "none", this.input = o("textarea", void 0), this.input.rows = 1, this.input.placeholder = ((U = r.i18n) == null ? void 0 : U.placeholder) ?? "Message…";
|
|
349
|
+
const h = o("button", "ocw-sendbtn");
|
|
350
|
+
h.type = "button";
|
|
351
|
+
const v = (T = r.i18n) == null ? void 0 : T.send;
|
|
352
|
+
v ? (h.textContent = v, h.classList.add("ocw-sendbtn-label"), h.setAttribute("aria-label", v)) : (h.innerHTML = Fe, h.setAttribute("aria-label", "Send message")), h.disabled = !0, this.sendBtn = h, h.addEventListener("click", () => this.flushSend()), this.input.addEventListener("input", () => {
|
|
353
|
+
var m, S;
|
|
354
|
+
this.sendBtn.disabled = this.input.value.trim().length === 0, this.autoGrowInput(), this.storeRef && !this.storeRef.messages().some((q) => q.senderRole === "guest") ? (S = (m = this.h).onDeflectQuery) == null || S.call(m, this.input.value) : this.hideDeflection();
|
|
355
|
+
}), this.input.addEventListener("keydown", (m) => {
|
|
356
|
+
m.isComposing || m.keyCode === 229 || (m.key === "Enter" && !m.shiftKey ? (m.preventDefault(), this.flushSend()) : this.signalTyping());
|
|
332
357
|
});
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
var
|
|
338
|
-
(
|
|
358
|
+
const c = o("button", "ocw-attach", "📎");
|
|
359
|
+
c.title = "Attach image or file";
|
|
360
|
+
const u = document.createElement("input");
|
|
361
|
+
u.type = "file", u.accept = "image/*,.pdf,.txt,.doc,.docx", u.style.display = "none", c.addEventListener("click", () => u.click()), u.addEventListener("change", () => {
|
|
362
|
+
var m;
|
|
363
|
+
(m = u.files) != null && m[0] && this.h.onAttach && this.h.onAttach(u.files[0]), u.value = "";
|
|
339
364
|
});
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
const
|
|
343
|
-
((
|
|
344
|
-
for (const
|
|
345
|
-
const S =
|
|
346
|
-
S.style.background =
|
|
347
|
-
this.cobrowseColor =
|
|
348
|
-
for (const
|
|
365
|
+
const l = o("div", "ocw-input");
|
|
366
|
+
l.append(c, u, this.input, h);
|
|
367
|
+
const E = o("div", "ocw-footer");
|
|
368
|
+
((B = r.i18n) == null ? void 0 : B.poweredBy) !== void 0 ? E.textContent = r.i18n.poweredBy : E.innerHTML = 'Powered by <a href="https://relay.paramms.com" target="_blank" rel="noopener">Relay</a>', this.footer = E, e.append(a, this.chips, this.scroll, this.typing, this.quick, this.formHost, this.csatPanel, this.offlinePanel, this.preChatPanel, this.deflectPanel, l, this.footer), this.cobrowseCanvas = o("canvas", "ocw-cobrowse-canvas"), this.cobrowseToolbar = o("div", "ocw-cobrowse-toolbar");
|
|
369
|
+
for (const m of ["#f5713c", "#1c1b1a", "#2563eb", "#16a34a", "#dc2626"]) {
|
|
370
|
+
const S = o("button", "ocw-cobrowse-swatch");
|
|
371
|
+
S.style.background = m, S.type = "button", m === this.cobrowseColor && S.classList.add("sel"), S.addEventListener("click", () => {
|
|
372
|
+
this.cobrowseColor = m;
|
|
373
|
+
for (const q of this.cobrowseToolbar.querySelectorAll(".ocw-cobrowse-swatch")) q.classList.remove("sel");
|
|
349
374
|
S.classList.add("sel");
|
|
350
375
|
}), this.cobrowseToolbar.append(S);
|
|
351
376
|
}
|
|
352
|
-
const
|
|
353
|
-
|
|
354
|
-
var
|
|
355
|
-
return (S = (
|
|
356
|
-
}), this.cobrowseToolbar.append(
|
|
377
|
+
const g = o("button", "ocw-cobrowse-clear", "Clear");
|
|
378
|
+
g.addEventListener("click", () => {
|
|
379
|
+
var m, S;
|
|
380
|
+
return (S = (m = this.h).onAnnotateClear) == null ? void 0 : S.call(m);
|
|
381
|
+
}), this.cobrowseToolbar.append(g), this.cobrowseHint = o("div", "ocw-cobrowse-hint", "🖍 Draw to point things out — visible to both sides"), e.append(this.cobrowseCanvas, this.cobrowseToolbar, this.cobrowseHint), this.bindCobrowsePointerEvents();
|
|
382
|
+
const w = (m) => {
|
|
383
|
+
e.classList.toggle("ocw-compact", m > 0 && m < _e);
|
|
384
|
+
};
|
|
385
|
+
w(e.clientWidth), typeof ResizeObserver < "u" && (this.compactObserver = new ResizeObserver((m) => {
|
|
386
|
+
var q;
|
|
387
|
+
const S = ((q = m[0]) == null ? void 0 : q.contentRect.width) ?? e.clientWidth;
|
|
388
|
+
w(S);
|
|
389
|
+
}), this.compactObserver.observe(e));
|
|
357
390
|
}
|
|
358
391
|
/** Returns the scroll container so history.ts can attach scroll listeners. */
|
|
359
392
|
getScrollEl() {
|
|
@@ -366,48 +399,51 @@ class Ee {
|
|
|
366
399
|
}
|
|
367
400
|
/** Call when the widget is unmounted. Disconnects scroll listeners and clears timers. */
|
|
368
401
|
destroy() {
|
|
369
|
-
var e;
|
|
370
|
-
(e = this.scrollCleanup) == null || e.call(this), this.scrollCleanup = null, this.typingTimer && (clearTimeout(this.typingTimer), this.typingTimer = null);
|
|
402
|
+
var e, i;
|
|
403
|
+
(e = this.scrollCleanup) == null || e.call(this), this.scrollCleanup = null, this.typingTimer && (clearTimeout(this.typingTimer), this.typingTimer = null), (i = this.compactObserver) == null || i.disconnect(), this.compactObserver = null;
|
|
371
404
|
}
|
|
372
|
-
/** Render list rows, optionally filtered by search query. */
|
|
373
|
-
/** Build a single WhatsApp-style conversation row. */
|
|
374
|
-
/** Returns true when the chat screen is visible (not the list). */
|
|
375
|
-
/** Navigate to the chat screen (slide list left, slide chat in from right). */
|
|
376
|
-
/** Navigate back to the list screen. */
|
|
377
405
|
flushSend() {
|
|
378
406
|
this.hideDeflection();
|
|
379
407
|
const e = this.input.value.trim();
|
|
380
|
-
e && (this.input.value = "", this.h.onTyping(!1), this.h.onSend(e));
|
|
408
|
+
e && (this.input.value = "", this.sendBtn.disabled = !0, this.autoGrowInput(), this.h.onTyping(!1), this.h.onSend(e));
|
|
409
|
+
}
|
|
410
|
+
/** Grow the composer with its content (up to the CSS max-height), collapse
|
|
411
|
+
* when cleared. scrollHeight is 0 in non-layout environments (jsdom) —
|
|
412
|
+
* skip there so tests and SSR-ish mounts are unaffected. */
|
|
413
|
+
autoGrowInput() {
|
|
414
|
+
this.input.style.height = "auto";
|
|
415
|
+
const e = this.input.scrollHeight;
|
|
416
|
+
e > 0 ? this.input.style.height = `${Math.min(e, 120)}px` : this.input.style.removeProperty("height");
|
|
381
417
|
}
|
|
382
418
|
signalTyping() {
|
|
383
419
|
const e = this.input.value.trim().slice(0, 100) || void 0;
|
|
384
420
|
this.h.onTyping(!0, e), this.typingTimer && clearTimeout(this.typingTimer), this.typingTimer = setTimeout(() => this.h.onTyping(!1), 2e3);
|
|
385
421
|
}
|
|
386
422
|
render(e) {
|
|
387
|
-
var
|
|
423
|
+
var c, u, l, E, g;
|
|
388
424
|
if (this.storeRef = e, this.cobrowseBtn.classList.toggle("show", !!e.subject), !e.subject && this.cobrowseActive && (this.cobrowseActive = !1, this.updateCobrowseUI()), this.cobrowseActive && e.annotationVersion !== this.lastAnnotationVersion && (this.lastAnnotationVersion = e.annotationVersion, this.resizeCobrowseCanvas(), this.redrawCobrowse()), e.accent && this.root.style.setProperty("--ocw-accent", e.accent), this.e2eBadge.style.display = e.e2e ? "inline-flex" : "none", this.buildSubjectCard(e), e.subject) {
|
|
389
|
-
const
|
|
390
|
-
|
|
425
|
+
const w = (c = this.cfg.subject) == null ? void 0 : c.ownerLabel;
|
|
426
|
+
w && (this.headerName.textContent = w);
|
|
391
427
|
}
|
|
392
428
|
this.quick.style.display = e.messages().length === 0 ? "flex" : "none", this.chips.replaceChildren();
|
|
393
429
|
const i = e.visibleActions();
|
|
394
430
|
this.chips.style.display = i.length ? "flex" : "none";
|
|
395
|
-
for (const
|
|
396
|
-
const s = this.scroll.scrollHeight,
|
|
431
|
+
for (const w of i) this.chips.append(this.chipEl(w));
|
|
432
|
+
const s = this.scroll.scrollHeight, r = this.scroll.scrollTop;
|
|
397
433
|
if (this.scroll.replaceChildren(), this.subjectCard.childNodes.length && this.scroll.append(this.subjectCard), e.hasMoreHistory) {
|
|
398
|
-
const
|
|
399
|
-
|
|
434
|
+
const w = o("div", "ocw-load-more");
|
|
435
|
+
w.textContent = "↑ Loading earlier messages…", w.style.pointerEvents = "none", this.scroll.append(w);
|
|
400
436
|
}
|
|
401
|
-
let
|
|
402
|
-
for (const
|
|
403
|
-
this.scroll.append(this.messageEl(
|
|
404
|
-
|
|
437
|
+
let a = 0;
|
|
438
|
+
for (const w of e.messages())
|
|
439
|
+
this.scroll.append(this.messageEl(w, e)), w.senderId !== this.me && w.seq > a && (a = w.seq);
|
|
440
|
+
r > 20 ? this.scroll.scrollTop = this.scroll.scrollHeight - s + r : this.scroll.scrollTop = this.scroll.scrollHeight, a > 0 && this.h.onReadUpTo(a);
|
|
405
441
|
const f = [...e.typing];
|
|
406
442
|
this.typing.classList.toggle("active", f.length > 0);
|
|
407
443
|
const b = this.typing.querySelector(".ocw-typing-bubble");
|
|
408
444
|
b && b.setAttribute("aria-label", f.length ? "typing" : ""), this.footer.style.display = e.whiteLabel ? "none" : "block";
|
|
409
|
-
const d = e.messages().some((
|
|
410
|
-
!!((u = e.preChat) != null && u.enabled) && !this.preChatDone && !d && (e.preChat.showWhen !== "offline" || e.offline) ? (this.preChatBuilt || this.buildPreChatPanel(e.preChat), this.preChatPanel.style.display = "block", this.offlinePanel.style.display = "none", (l = this.root.querySelector(".ocw-input")) == null || l.style.setProperty("display", "none")) : (this.preChatPanel.style.display = "none", e.offline ? (this.offlinePanel.style.display === "none" && this.buildOfflinePanel(e.offlineMessage), this.offlinePanel.style.display = "block", (
|
|
445
|
+
const d = e.messages().some((w) => w.senderRole === "guest");
|
|
446
|
+
!!((u = e.preChat) != null && u.enabled) && !this.preChatDone && !d && (e.preChat.showWhen !== "offline" || e.offline) ? (this.preChatBuilt || this.buildPreChatPanel(e.preChat), this.preChatPanel.style.display = "block", this.offlinePanel.style.display = "none", (l = this.root.querySelector(".ocw-input")) == null || l.style.setProperty("display", "none")) : (this.preChatPanel.style.display = "none", e.offline ? (this.offlinePanel.style.display === "none" && this.buildOfflinePanel(e.offlineMessage), this.offlinePanel.style.display = "block", (E = this.root.querySelector(".ocw-input")) == null || E.style.setProperty("display", "none")) : (this.offlinePanel.style.display = "none", (g = this.root.querySelector(".ocw-input")) == null || g.style.removeProperty("display")));
|
|
411
447
|
const v = ["resolved", "closed", "sold", "issued", "checked_out"];
|
|
412
448
|
this.h.onCsat && !this.csatSubmitted && v.includes(e.state) && e.messages().length > 0 && (this.csatPanel.style.display === "none" && this.buildCsatPanel(), this.csatPanel.style.display = "block");
|
|
413
449
|
}
|
|
@@ -422,67 +458,67 @@ class Ee {
|
|
|
422
458
|
}
|
|
423
459
|
buildOfflinePanel(e) {
|
|
424
460
|
var b;
|
|
425
|
-
this.offlinePanel.replaceChildren(), this.offlinePanel.append(
|
|
426
|
-
const i =
|
|
461
|
+
this.offlinePanel.replaceChildren(), this.offlinePanel.append(o("div", "ocw-offline-icon", "🌙")), this.offlinePanel.append(o("div", "ocw-offline-title", ((b = this.cfg.i18n) == null ? void 0 : b.offline) ?? "We're offline right now")), this.offlinePanel.append(o("div", "ocw-offline-msg", e || "Leave your details and we'll get back to you soon."));
|
|
462
|
+
const i = o("div", "ocw-offline-form"), s = o("input", "ocw-offline-input");
|
|
427
463
|
s.placeholder = "Your name", s.type = "text";
|
|
428
|
-
const
|
|
429
|
-
|
|
430
|
-
const
|
|
431
|
-
|
|
432
|
-
const f =
|
|
433
|
-
f.addEventListener("click", () => {
|
|
434
|
-
!
|
|
464
|
+
const r = o("input", "ocw-offline-input");
|
|
465
|
+
r.placeholder = "Your email", r.type = "email";
|
|
466
|
+
const a = o("textarea", "ocw-offline-input");
|
|
467
|
+
a.placeholder = "Your message", a.rows = 3;
|
|
468
|
+
const f = o("button", "ocw-offline-submit", "Send message");
|
|
469
|
+
f.type = "button", f.addEventListener("click", () => {
|
|
470
|
+
!r.value.trim() || !a.value.trim() || (f.disabled = !0, this.h.onSend(`[Offline form]
|
|
435
471
|
Name: ${s.value || "Anonymous"}
|
|
436
|
-
Email: ${
|
|
437
|
-
Message: ${
|
|
438
|
-
}), i.append(s,
|
|
472
|
+
Email: ${r.value}
|
|
473
|
+
Message: ${a.value}`), this.offlinePanel.replaceChildren(o("div", "ocw-offline-thanks", "✓ Message sent! We'll reply to your email.")));
|
|
474
|
+
}), i.append(s, r, a, f), this.offlinePanel.append(i);
|
|
439
475
|
}
|
|
440
476
|
buildPreChatPanel(e) {
|
|
441
477
|
var d;
|
|
442
|
-
this.preChatBuilt = !0, this.preChatPanel.replaceChildren(), this.preChatPanel.append(
|
|
443
|
-
const i =
|
|
444
|
-
for (const
|
|
445
|
-
const v =
|
|
446
|
-
v.type =
|
|
478
|
+
this.preChatBuilt = !0, this.preChatPanel.replaceChildren(), this.preChatPanel.append(o("div", "ocw-prechat-title", e.title ?? "Before we start…"));
|
|
479
|
+
const i = o("div", "ocw-offline-form"), s = {};
|
|
480
|
+
for (const h of e.fields ?? ["name", "email"]) {
|
|
481
|
+
const v = o("input", "ocw-offline-input");
|
|
482
|
+
v.type = h === "email" ? "email" : h === "phone" ? "tel" : "text", v.placeholder = h === "name" ? "Your name" : h === "email" ? "Your email" : "Your phone number", s[h] = v, i.append(v);
|
|
447
483
|
}
|
|
448
|
-
let
|
|
484
|
+
let r = null;
|
|
449
485
|
if ((d = e.topics) != null && d.length) {
|
|
450
|
-
|
|
451
|
-
const
|
|
452
|
-
|
|
486
|
+
r = o("select", void 0);
|
|
487
|
+
const h = document.createElement("option");
|
|
488
|
+
h.value = "", h.textContent = "What is this about?", r.append(h);
|
|
453
489
|
for (const v of e.topics) {
|
|
454
|
-
const
|
|
455
|
-
|
|
490
|
+
const c = document.createElement("option");
|
|
491
|
+
c.value = v, c.textContent = v, r.append(c);
|
|
456
492
|
}
|
|
457
|
-
i.append(
|
|
493
|
+
i.append(r);
|
|
458
494
|
}
|
|
459
|
-
let
|
|
495
|
+
let a = null, f = null;
|
|
460
496
|
if (e.callbackOption) {
|
|
461
|
-
const
|
|
462
|
-
|
|
497
|
+
const h = o("label", "ocw-prechat-cb");
|
|
498
|
+
a = document.createElement("input"), a.type = "checkbox", h.append(a, document.createTextNode("📞 Request a call back")), i.append(h), s.phone || (f = o("input", "ocw-offline-input"), f.type = "tel", f.placeholder = "Phone number for the call", f.style.display = "none", a.addEventListener("change", () => f.style.setProperty("display", a.checked ? "block" : "none")), i.append(f));
|
|
463
499
|
}
|
|
464
|
-
const b =
|
|
465
|
-
b.addEventListener("click", () => {
|
|
466
|
-
var u, l,
|
|
467
|
-
const
|
|
468
|
-
if (s.email && (!
|
|
500
|
+
const b = o("button", "ocw-offline-submit", "Start chat");
|
|
501
|
+
b.type = "button", b.addEventListener("click", () => {
|
|
502
|
+
var u, l, E, g, w, k, I;
|
|
503
|
+
const h = (u = s.email) == null ? void 0 : u.value.trim();
|
|
504
|
+
if (s.email && (!h || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(h))) {
|
|
469
505
|
s.email.focus();
|
|
470
506
|
return;
|
|
471
507
|
}
|
|
472
|
-
const v = !!(
|
|
473
|
-
if (v && !
|
|
474
|
-
(
|
|
508
|
+
const v = !!(a != null && a.checked), c = (((l = s.phone) == null ? void 0 : l.value) ?? (f == null ? void 0 : f.value) ?? "").trim();
|
|
509
|
+
if (v && !c) {
|
|
510
|
+
(E = s.phone ?? f) == null || E.focus();
|
|
475
511
|
return;
|
|
476
512
|
}
|
|
477
|
-
if (
|
|
478
|
-
|
|
513
|
+
if (r && ((g = e.topics) != null && g.length) && !r.value) {
|
|
514
|
+
r.focus();
|
|
479
515
|
return;
|
|
480
516
|
}
|
|
481
|
-
this.completePreChat(), (
|
|
482
|
-
...(
|
|
483
|
-
...
|
|
484
|
-
...
|
|
485
|
-
...
|
|
517
|
+
b.disabled = !0, this.completePreChat(), (I = (k = this.h).onPreChat) == null || I.call(k, {
|
|
518
|
+
...(w = s.name) != null && w.value.trim() ? { name: s.name.value.trim() } : {},
|
|
519
|
+
...h ? { email: h } : {},
|
|
520
|
+
...c ? { phone: c } : {},
|
|
521
|
+
...r != null && r.value ? { topic: r.value } : {},
|
|
486
522
|
...v ? { callback: !0 } : {}
|
|
487
523
|
});
|
|
488
524
|
}), i.append(b), this.preChatPanel.append(i);
|
|
@@ -494,10 +530,10 @@ Message: ${c.value}`), this.offlinePanel.replaceChildren(t("div", "ocw-offline-t
|
|
|
494
530
|
/** KB deflection results ("was this your question?") above the composer. */
|
|
495
531
|
showDeflection(e) {
|
|
496
532
|
if (!e.length) return this.hideDeflection();
|
|
497
|
-
this.deflectPanel.replaceChildren(), this.deflectPanel.append(
|
|
533
|
+
this.deflectPanel.replaceChildren(), this.deflectPanel.append(o("div", "ocw-deflect-hint", "Instant answers — tap to expand"));
|
|
498
534
|
for (const i of e.slice(0, 3)) {
|
|
499
|
-
const s =
|
|
500
|
-
s.append(
|
|
535
|
+
const s = o("button", "ocw-deflect-card");
|
|
536
|
+
s.append(o("div", "ocw-deflect-q", i.title), o("div", "ocw-deflect-a", i.answer)), s.addEventListener("click", () => s.classList.toggle("open")), this.deflectPanel.append(s);
|
|
501
537
|
}
|
|
502
538
|
this.deflectPanel.style.display = "flex";
|
|
503
539
|
}
|
|
@@ -505,19 +541,17 @@ Message: ${c.value}`), this.offlinePanel.replaceChildren(t("div", "ocw-offline-t
|
|
|
505
541
|
this.deflectPanel.style.display = "none", this.deflectPanel.replaceChildren();
|
|
506
542
|
}
|
|
507
543
|
buildCsatPanel() {
|
|
508
|
-
this.csatPanel.replaceChildren(), this.csatPanel.append(
|
|
509
|
-
const e =
|
|
544
|
+
this.csatPanel.replaceChildren(), this.csatPanel.append(o("div", "ocw-csat-title", "How did we do?"));
|
|
545
|
+
const e = o("div", "ocw-csat-stars"), i = [];
|
|
510
546
|
for (let s = 1; s <= 5; s++) {
|
|
511
|
-
const
|
|
512
|
-
|
|
513
|
-
var
|
|
514
|
-
this.csatSubmitted = !0, this.csatPanel.replaceChildren(
|
|
515
|
-
}), i.push(
|
|
547
|
+
const r = o("button", "ocw-csat-star", "★");
|
|
548
|
+
r.dataset.score = String(s), r.addEventListener("mouseenter", () => i.forEach((a, f) => a.classList.toggle("lit", f < s))), r.addEventListener("mouseleave", () => i.forEach((a) => a.classList.remove("lit"))), r.addEventListener("click", () => {
|
|
549
|
+
var a, f;
|
|
550
|
+
this.csatSubmitted = !0, this.csatPanel.replaceChildren(o("div", "ocw-csat-done", `Thanks for your ${s}★ rating!`)), (f = (a = this.h).onCsat) == null || f.call(a, s);
|
|
551
|
+
}), i.push(r), e.append(r);
|
|
516
552
|
}
|
|
517
553
|
this.csatPanel.append(e);
|
|
518
554
|
}
|
|
519
|
-
/** Subject card from the server's Subject entity (per chatroom), with the
|
|
520
|
-
* mount config as a fallback. Built once when data first arrives. */
|
|
521
555
|
// ── Co-browsing (shared whiteboard) ──────────────────────────────────────
|
|
522
556
|
updateCobrowseUI() {
|
|
523
557
|
this.cobrowseCanvas.classList.toggle("active", this.cobrowseActive), this.cobrowseToolbar.classList.toggle("active", this.cobrowseActive), this.cobrowseHint.classList.toggle("active", this.cobrowseActive), this.cobrowseBtn.classList.toggle("on", this.cobrowseActive), this.cobrowseActive && (this.resizeCobrowseCanvas(), this.redrawCobrowse());
|
|
@@ -530,9 +564,9 @@ Message: ${c.value}`), this.offlinePanel.replaceChildren(t("div", "ocw-offline-t
|
|
|
530
564
|
drawStroke(e) {
|
|
531
565
|
const i = this.cobrowseCanvas.getContext("2d");
|
|
532
566
|
if (!i || e.points.length < 2) return;
|
|
533
|
-
const s = this.cobrowseCanvas.width,
|
|
534
|
-
i.strokeStyle = e.color, i.lineWidth = Math.max(1, e.width * Math.min(s,
|
|
535
|
-
for (const
|
|
567
|
+
const s = this.cobrowseCanvas.width, r = this.cobrowseCanvas.height;
|
|
568
|
+
i.strokeStyle = e.color, i.lineWidth = Math.max(1, e.width * Math.min(s, r)), i.lineJoin = "round", i.lineCap = "round", i.beginPath(), i.moveTo(e.points[0].x * s, e.points[0].y * r);
|
|
569
|
+
for (const a of e.points.slice(1)) i.lineTo(a.x * s, a.y * r);
|
|
536
570
|
i.stroke();
|
|
537
571
|
}
|
|
538
572
|
redrawCobrowse() {
|
|
@@ -546,40 +580,40 @@ Message: ${c.value}`), this.offlinePanel.replaceChildren(t("div", "ocw-offline-t
|
|
|
546
580
|
bindCobrowsePointerEvents() {
|
|
547
581
|
let e = !1, i = [];
|
|
548
582
|
const s = (f) => {
|
|
549
|
-
const b = this.cobrowseCanvas.getBoundingClientRect(), d = b.width > 0 ? (f.clientX - b.left) / b.width : 0,
|
|
550
|
-
return { x: Math.min(1, Math.max(0, d)), y: Math.min(1, Math.max(0,
|
|
551
|
-
},
|
|
583
|
+
const b = this.cobrowseCanvas.getBoundingClientRect(), d = b.width > 0 ? (f.clientX - b.left) / b.width : 0, h = b.height > 0 ? (f.clientY - b.top) / b.height : 0;
|
|
584
|
+
return { x: Math.min(1, Math.max(0, d)), y: Math.min(1, Math.max(0, h)) };
|
|
585
|
+
}, r = 6e-3;
|
|
552
586
|
this.cobrowseCanvas.addEventListener("pointerdown", (f) => {
|
|
553
587
|
this.cobrowseActive && (e = !0, i = [s(f)], this.cobrowseCanvas.setPointerCapture(f.pointerId));
|
|
554
588
|
}), this.cobrowseCanvas.addEventListener("pointermove", (f) => {
|
|
555
|
-
e && (i.push(s(f)), this.redrawCobrowse(), this.drawStroke({ points: i, color: this.cobrowseColor, width:
|
|
589
|
+
e && (i.push(s(f)), this.redrawCobrowse(), this.drawStroke({ points: i, color: this.cobrowseColor, width: r }));
|
|
556
590
|
});
|
|
557
|
-
const
|
|
591
|
+
const a = (f) => {
|
|
558
592
|
var b, d;
|
|
559
593
|
if (e) {
|
|
560
|
-
e = !1, i.length > 1 && ((d = (b = this.h).onAnnotate) == null || d.call(b, { id: `an_${Date.now()}_${Math.random().toString(36).slice(2)}`, points: i, color: this.cobrowseColor, width:
|
|
594
|
+
e = !1, i.length > 1 && ((d = (b = this.h).onAnnotate) == null || d.call(b, { id: `an_${Date.now()}_${Math.random().toString(36).slice(2)}`, points: i, color: this.cobrowseColor, width: r })), i = [];
|
|
561
595
|
try {
|
|
562
596
|
this.cobrowseCanvas.releasePointerCapture(f.pointerId);
|
|
563
597
|
} catch {
|
|
564
598
|
}
|
|
565
599
|
}
|
|
566
600
|
};
|
|
567
|
-
this.cobrowseCanvas.addEventListener("pointerup",
|
|
601
|
+
this.cobrowseCanvas.addEventListener("pointerup", a), this.cobrowseCanvas.addEventListener("pointercancel", a);
|
|
568
602
|
}
|
|
569
603
|
buildSubjectCard(e) {
|
|
570
604
|
if (this.subjectBuilt) return;
|
|
571
|
-
const i = e.subject, s = this.cfg.subject,
|
|
572
|
-
if (!
|
|
573
|
-
this.subjectBuilt = !0, this.subjectCard.replaceChildren(), this.subjectCard.append(
|
|
574
|
-
const
|
|
575
|
-
if (i) for (const [b, d] of Object.entries(i.fields))
|
|
576
|
-
else for (const b of (s == null ? void 0 : s.tags) ?? [])
|
|
577
|
-
|
|
605
|
+
const i = e.subject, s = this.cfg.subject, r = (i == null ? void 0 : i.title) ?? (s == null ? void 0 : s.title);
|
|
606
|
+
if (!r) return;
|
|
607
|
+
this.subjectBuilt = !0, this.subjectCard.replaceChildren(), this.subjectCard.append(o("div", "ocw-subject-title", r)), s != null && s.subtitle && this.subjectCard.append(o("div", "ocw-subject-sub", s.subtitle));
|
|
608
|
+
const a = o("div", "ocw-tags");
|
|
609
|
+
if (i) for (const [b, d] of Object.entries(i.fields)) a.append(o("span", "ocw-tag", `${b}: ${d}`));
|
|
610
|
+
else for (const b of (s == null ? void 0 : s.tags) ?? []) a.append(o("span", "ocw-tag", b));
|
|
611
|
+
a.childNodes.length && this.subjectCard.append(a);
|
|
578
612
|
const f = (i == null ? void 0 : i.state) ?? (s == null ? void 0 : s.status);
|
|
579
613
|
f && (this.statusBadge.textContent = f, this.statusBadge.style.display = "inline-flex");
|
|
580
614
|
}
|
|
581
615
|
chipEl(e) {
|
|
582
|
-
const i =
|
|
616
|
+
const i = o("button", "ocw-chip", e.icon ? `${e.icon} ${e.label}` : e.label);
|
|
583
617
|
return i.dataset.actionId = e.id, i.addEventListener("click", async () => {
|
|
584
618
|
var s;
|
|
585
619
|
e.confirm && !await this.confirm(e.label) || ((s = e.input) != null && s.length ? this.openForm(e) : this.h.onInvoke(e.id));
|
|
@@ -588,14 +622,14 @@ Message: ${c.value}`), this.offlinePanel.replaceChildren(t("div", "ocw-offline-t
|
|
|
588
622
|
/** In-widget confirmation modal (replaces window.confirm). */
|
|
589
623
|
confirm(e) {
|
|
590
624
|
return new Promise((i) => {
|
|
591
|
-
const s =
|
|
592
|
-
|
|
593
|
-
const
|
|
594
|
-
s.remove(), i(
|
|
625
|
+
const s = o("div", "ocw-modal"), r = o("div", "ocw-modal-card");
|
|
626
|
+
r.append(o("div", "ocw-modal-title", e)), r.append(o("div", "ocw-modal-body", `Confirm “${e}”?`));
|
|
627
|
+
const a = o("div", "ocw-modal-actions"), f = o("button", "ocw-modal-cancel", "Cancel"), b = o("button", "ocw-modal-ok", "Confirm"), d = (h) => {
|
|
628
|
+
s.remove(), i(h);
|
|
595
629
|
};
|
|
596
|
-
f.addEventListener("click", () => d(!1)), b.addEventListener("click", () => d(!0)), s.addEventListener("click", (
|
|
597
|
-
|
|
598
|
-
}),
|
|
630
|
+
f.addEventListener("click", () => d(!1)), b.addEventListener("click", () => d(!0)), s.addEventListener("click", (h) => {
|
|
631
|
+
h.target === s && d(!1);
|
|
632
|
+
}), a.append(f, b), r.append(a), s.append(r), this.root.append(s), b.focus();
|
|
599
633
|
});
|
|
600
634
|
}
|
|
601
635
|
/** Inline form for a form-effect action: typed inputs (date picker, number,
|
|
@@ -603,167 +637,169 @@ Message: ${c.value}`), this.offlinePanel.replaceChildren(t("div", "ocw-offline-t
|
|
|
603
637
|
openForm(e) {
|
|
604
638
|
var b, d;
|
|
605
639
|
this.formHost.replaceChildren();
|
|
606
|
-
const i =
|
|
607
|
-
i.append(
|
|
640
|
+
const i = o("div", "ocw-form");
|
|
641
|
+
i.append(o("div", "ocw-form-title", e.icon ? `${e.icon} ${e.label}` : e.label));
|
|
608
642
|
const s = /* @__PURE__ */ new Map();
|
|
609
|
-
for (const
|
|
610
|
-
const v =
|
|
611
|
-
if (v.append(
|
|
612
|
-
const
|
|
613
|
-
|
|
614
|
-
for (const u of
|
|
615
|
-
const l =
|
|
616
|
-
l.value = u, l.textContent = u,
|
|
643
|
+
for (const h of e.input ?? []) {
|
|
644
|
+
const v = o("label", "ocw-form-row");
|
|
645
|
+
if (v.append(o("span", "ocw-form-lbl", h.label)), h.type === "select" && ((b = h.options) != null && b.length)) {
|
|
646
|
+
const c = o("select", "ocw-form-input");
|
|
647
|
+
h.required || c.append(o("option", void 0, "— select —"));
|
|
648
|
+
for (const u of h.options) {
|
|
649
|
+
const l = o("option");
|
|
650
|
+
l.value = u, l.textContent = u, c.append(l);
|
|
617
651
|
}
|
|
618
|
-
|
|
652
|
+
h.required && (c.required = !0), v.append(c), s.set(h.name, c);
|
|
619
653
|
} else {
|
|
620
|
-
const
|
|
621
|
-
|
|
654
|
+
const c = o("input", "ocw-form-input");
|
|
655
|
+
c.type = h.type === "number" ? "number" : h.type === "date" ? "datetime-local" : "text", h.required && (c.required = !0), v.append(c), s.set(h.name, c);
|
|
622
656
|
}
|
|
623
657
|
i.append(v);
|
|
624
658
|
}
|
|
625
|
-
const
|
|
626
|
-
|
|
627
|
-
const
|
|
628
|
-
for (const [v,
|
|
629
|
-
if (
|
|
630
|
-
|
|
659
|
+
const r = o("div", "ocw-form-actions"), a = o("button", "ocw-form-cancel", "Cancel"), f = o("button", "ocw-form-submit", "Send");
|
|
660
|
+
a.addEventListener("click", () => this.formHost.replaceChildren()), f.addEventListener("click", () => {
|
|
661
|
+
const h = {};
|
|
662
|
+
for (const [v, c] of s) {
|
|
663
|
+
if (c.required && !c.value) {
|
|
664
|
+
c.style.borderColor = "#e5484d";
|
|
631
665
|
return;
|
|
632
666
|
}
|
|
633
|
-
|
|
667
|
+
h[v] = c.type === "number" ? Number(c.value) : c.value;
|
|
634
668
|
}
|
|
635
|
-
this.formHost.replaceChildren(), this.h.onInvoke(e.id,
|
|
636
|
-
}),
|
|
669
|
+
this.formHost.replaceChildren(), this.h.onInvoke(e.id, h);
|
|
670
|
+
}), r.append(a, f), i.append(r), this.formHost.append(i), (d = s.values().next().value) == null || d.focus();
|
|
637
671
|
}
|
|
638
672
|
messageEl(e, i) {
|
|
639
|
-
var
|
|
673
|
+
var c;
|
|
640
674
|
if (e.senderRole === "system") {
|
|
641
|
-
const u =
|
|
642
|
-
return u.textContent = e.deletedAt ? "message deleted" :
|
|
675
|
+
const u = o("div", "ocw-sys");
|
|
676
|
+
return u.textContent = e.deletedAt ? "message deleted" : ie(e.content), u;
|
|
643
677
|
}
|
|
644
|
-
const s = e.senderId === this.me,
|
|
645
|
-
!s && !
|
|
646
|
-
const f =
|
|
678
|
+
const s = e.senderId === this.me, r = !!e.internal, a = o("div", `ocw-row ${r ? "ocw-note mine" : s ? "mine" : "theirs"} ${e.senderRole === "bot" ? "ocw-bot" : ""}`);
|
|
679
|
+
!s && !r && a.append(o("div", "ocw-dot", e.senderRole === "bot" ? "🤖" : "🧑"));
|
|
680
|
+
const f = o("div"), b = o("div", "ocw-bubble-wrap");
|
|
647
681
|
if (e.replyToId) {
|
|
648
|
-
const u =
|
|
682
|
+
const u = o("div", "ocw-reply-to", "↩ replying to a message");
|
|
649
683
|
u.style.cssText = "font-size:11px;color:var(--ocw-mut);margin-bottom:2px;font-style:italic", f.append(u);
|
|
650
684
|
}
|
|
651
|
-
const d =
|
|
652
|
-
let
|
|
653
|
-
if (e.deletedAt) d.append(
|
|
685
|
+
const d = o("div", "ocw-bubble");
|
|
686
|
+
let h = null;
|
|
687
|
+
if (e.deletedAt) d.append(o("span", "ocw-deleted", "message deleted"));
|
|
654
688
|
else if (e.content.kind === "attachment") {
|
|
655
689
|
const u = e.content;
|
|
656
|
-
if ((
|
|
690
|
+
if ((c = u.mime) != null && c.startsWith("image/")) {
|
|
657
691
|
const l = document.createElement("img");
|
|
658
692
|
l.src = u.url, l.alt = u.name ?? "image", l.style.cssText = "max-width:220px;max-height:160px;border-radius:10px;display:block;cursor:pointer", l.addEventListener("click", () => window.open(u.url, "_blank")), d.append(l);
|
|
659
693
|
} else {
|
|
660
694
|
const l = document.createElement("a");
|
|
661
|
-
l.href = u.url, l.target = "_blank", l.rel = "noopener", l.style.cssText = "display:flex;align-items:center;gap:8px;color:inherit;text-decoration:none", l.append(
|
|
695
|
+
l.href = u.url, l.target = "_blank", l.rel = "noopener", l.style.cssText = "display:flex;align-items:center;gap:8px;color:inherit;text-decoration:none", l.append(o("span", void 0, "📄"), o("span", void 0, u.name ?? "file")), d.append(l);
|
|
662
696
|
}
|
|
663
697
|
} else if (e.content.kind === "appointment") {
|
|
664
|
-
const u = e.content, l =
|
|
665
|
-
l.append(
|
|
666
|
-
const
|
|
667
|
-
|
|
668
|
-
const
|
|
669
|
-
|
|
698
|
+
const u = e.content, l = o("div", "ocw-appt");
|
|
699
|
+
l.append(o("div", "ocw-appt-title", `📅 ${u.title}`)), l.append(o("div", "ocw-appt-time", new Date(u.startIso).toLocaleString() + " – " + new Date(u.endIso).toLocaleTimeString())), u.location && l.append(o("div", "ocw-appt-loc", `📍 ${u.location}`)), u.description && l.append(o("div", "ocw-appt-desc", u.description));
|
|
700
|
+
const E = o("div", "ocw-appt-links"), g = document.createElement("a");
|
|
701
|
+
g.href = u.googleUrl, g.target = "_blank", g.rel = "noopener", g.className = "ocw-appt-btn", g.textContent = "📅 Add to Google Calendar";
|
|
702
|
+
const w = document.createElement("a");
|
|
703
|
+
w.href = u.icalUrl, w.download = `${u.title}.ics`, w.className = "ocw-appt-btn ocw-appt-btn-sec", w.textContent = "🍎 Apple / iCal", E.append(g, w), l.append(E), d.append(l);
|
|
670
704
|
} else
|
|
671
|
-
|
|
672
|
-
if (b.append(d), !s && !
|
|
705
|
+
h = document.createTextNode(ie(e.content)), d.append(h), e.editedAt && d.append(o("span", "ocw-edited", "(edited)"));
|
|
706
|
+
if (b.append(d), !s && !r && this.h.onTranslate && e.content.kind === "text" && !e.deletedAt && e.seq > 0 && h) {
|
|
673
707
|
const u = e.content.text;
|
|
674
708
|
if (u.trim()) {
|
|
675
|
-
const l =
|
|
676
|
-
l.type = "button", l.title = "Translate", l.addEventListener("click", (
|
|
677
|
-
if (
|
|
678
|
-
this.showingTranslation.delete(e.id),
|
|
709
|
+
const l = o("button", "ocw-translate-btn", "🌐");
|
|
710
|
+
l.type = "button", l.title = "Translate", l.addEventListener("click", (E) => {
|
|
711
|
+
if (E.stopPropagation(), this.showingTranslation.has(e.id)) {
|
|
712
|
+
this.showingTranslation.delete(e.id), h.textContent = u, l.textContent = "🌐", l.title = "Translate";
|
|
679
713
|
return;
|
|
680
714
|
}
|
|
681
|
-
const
|
|
682
|
-
if (
|
|
683
|
-
this.showingTranslation.add(e.id),
|
|
715
|
+
const g = this.translationCache.get(e.id);
|
|
716
|
+
if (g !== void 0) {
|
|
717
|
+
this.showingTranslation.add(e.id), h.textContent = g, l.textContent = "↩", l.title = "Show original";
|
|
684
718
|
return;
|
|
685
719
|
}
|
|
686
|
-
l.textContent = "⏳", this.h.onTranslate(u).then((
|
|
687
|
-
if (
|
|
720
|
+
l.textContent = "⏳", this.h.onTranslate(u).then((w) => {
|
|
721
|
+
if (w === null) {
|
|
688
722
|
l.textContent = "⚠️", l.title = "Translation unavailable", setTimeout(() => {
|
|
689
723
|
l.textContent = "🌐", l.title = "Translate";
|
|
690
724
|
}, 1500);
|
|
691
725
|
return;
|
|
692
726
|
}
|
|
693
|
-
this.translationCache.set(e.id,
|
|
727
|
+
this.translationCache.set(e.id, w), this.showingTranslation.add(e.id), h.textContent = w, l.textContent = "↩", l.title = "Show original";
|
|
694
728
|
});
|
|
695
729
|
}), b.append(l);
|
|
696
730
|
}
|
|
697
731
|
}
|
|
698
732
|
if (s && !e.deletedAt && e.seq > 0 && (this.h.onEdit ?? this.h.onDelete)) {
|
|
699
|
-
const u =
|
|
733
|
+
const u = o("div", "ocw-msg-menu");
|
|
700
734
|
if (this.h.onEdit) {
|
|
701
|
-
const l =
|
|
702
|
-
l.title = "Edit", l.addEventListener("click", (
|
|
703
|
-
|
|
704
|
-
const
|
|
705
|
-
|
|
706
|
-
const
|
|
707
|
-
|
|
708
|
-
const
|
|
709
|
-
|
|
710
|
-
const
|
|
711
|
-
|
|
712
|
-
const
|
|
713
|
-
|
|
714
|
-
const
|
|
715
|
-
|
|
716
|
-
const
|
|
717
|
-
|
|
718
|
-
}),
|
|
719
|
-
|
|
735
|
+
const l = o("button", void 0, "✏️");
|
|
736
|
+
l.title = "Edit", l.addEventListener("click", (E) => {
|
|
737
|
+
E.stopPropagation();
|
|
738
|
+
const g = ie(e.content), w = document.createElement("textarea");
|
|
739
|
+
w.value = g, w.rows = Math.min(4, Math.ceil(g.length / 40) + 1), w.style.cssText = "width:100%;resize:vertical;border:1px solid var(--ocw-accent);border-radius:8px;padding:6px 10px;font:inherit;font-size:14px;background:#fff;color:#1c1b1a;box-sizing:border-box";
|
|
740
|
+
const k = o("button", "ocw-form-submit", "Save");
|
|
741
|
+
k.style.cssText = "margin-top:6px;padding:5px 14px;font-size:13px";
|
|
742
|
+
const I = o("button", "ocw-form-cancel", "Cancel");
|
|
743
|
+
I.style.cssText = "margin-top:6px;padding:5px 10px;font-size:13px";
|
|
744
|
+
const j = o("div");
|
|
745
|
+
j.style.cssText = "display:flex;gap:6px;justify-content:flex-end", j.append(I, k);
|
|
746
|
+
const C = o("div");
|
|
747
|
+
C.append(w, j), d.replaceChildren(C), w.focus(), w.select();
|
|
748
|
+
const R = () => d.replaceChildren(h ?? document.createTextNode(g));
|
|
749
|
+
I.addEventListener("click", R), k.addEventListener("click", () => {
|
|
750
|
+
const A = w.value.trim();
|
|
751
|
+
A && A !== g && this.h.onEdit(e.id, A), R();
|
|
752
|
+
}), w.addEventListener("keydown", (A) => {
|
|
753
|
+
A.key === "Enter" && !A.shiftKey && (A.preventDefault(), k.click()), A.key === "Escape" && R();
|
|
720
754
|
});
|
|
721
755
|
}), u.append(l);
|
|
722
756
|
}
|
|
723
757
|
if (this.h.onDelete) {
|
|
724
|
-
const l =
|
|
725
|
-
l.title = "Delete", l.addEventListener("click", (
|
|
726
|
-
|
|
758
|
+
const l = o("button", "del", "🗑");
|
|
759
|
+
l.title = "Delete", l.addEventListener("click", (E) => {
|
|
760
|
+
E.stopPropagation(), this.h.onDelete(e.id);
|
|
727
761
|
}), u.append(l);
|
|
728
762
|
}
|
|
729
763
|
b.append(u);
|
|
730
764
|
}
|
|
731
765
|
if (f.append(b), this.h.onReact && !e.deletedAt && e.seq > 0) {
|
|
732
|
-
const u =
|
|
766
|
+
const u = o("div", "ocw-react-wrap"), l = o("div", "ocw-react");
|
|
733
767
|
if (e.reactions && Object.keys(e.reactions).length)
|
|
734
|
-
for (const [
|
|
735
|
-
const
|
|
736
|
-
|
|
737
|
-
var
|
|
738
|
-
return (
|
|
739
|
-
}), l.append(
|
|
768
|
+
for (const [w, k] of Object.entries(e.reactions)) {
|
|
769
|
+
const I = o("button", `ocw-react-pill${k.includes(this.me) ? " mine" : ""}`, `${w} ${k.length}`);
|
|
770
|
+
I.addEventListener("click", () => {
|
|
771
|
+
var j, C;
|
|
772
|
+
return (C = (j = this.h).onReact) == null ? void 0 : C.call(j, e.id, w, k.includes(this.me));
|
|
773
|
+
}), l.append(I);
|
|
740
774
|
}
|
|
741
|
-
const
|
|
742
|
-
for (const
|
|
743
|
-
const
|
|
744
|
-
|
|
745
|
-
var
|
|
746
|
-
|
|
747
|
-
const
|
|
748
|
-
(
|
|
749
|
-
}),
|
|
775
|
+
const E = o("button", "ocw-react-btn", "+"), g = o("div", "ocw-react-picker");
|
|
776
|
+
for (const w of Ne) {
|
|
777
|
+
const k = o("button", void 0, w);
|
|
778
|
+
k.addEventListener("click", (I) => {
|
|
779
|
+
var C, R, A, O;
|
|
780
|
+
I.stopPropagation();
|
|
781
|
+
const j = (R = (C = e.reactions) == null ? void 0 : C[w]) == null ? void 0 : R.includes(this.me);
|
|
782
|
+
(O = (A = this.h).onReact) == null || O.call(A, e.id, w, !!j), g.style.display = "none";
|
|
783
|
+
}), g.append(k);
|
|
750
784
|
}
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
785
|
+
g.style.display = "none", E.addEventListener("click", (w) => {
|
|
786
|
+
w.stopPropagation();
|
|
787
|
+
const k = g.style.display === "none";
|
|
788
|
+
g.style.display = k ? "flex" : "none", k && document.addEventListener("click", () => {
|
|
789
|
+
g.style.display = "none";
|
|
790
|
+
}, { once: !0 });
|
|
791
|
+
}), l.append(E), u.append(l, g), f.append(u);
|
|
792
|
+
} else e.reactions && Object.keys(e.reactions).length && f.append(o("div", "ocw-react", Object.entries(e.reactions).map(([u, l]) => `${u}${l.length}`).join(" ")));
|
|
793
|
+
const v = o("div", "ocw-time ocw-meta", Ve(e.ts));
|
|
758
794
|
if (s && e.status) {
|
|
759
|
-
const u =
|
|
795
|
+
const u = o("span", `ocw-tick${e.status === "read" ? " read" : e.status === "delivered" ? " delivered" : ""}`, Ke(e.status));
|
|
760
796
|
v.append(u);
|
|
761
797
|
}
|
|
762
|
-
return s && e.seq > 0 && i.lastReadByOthers >= e.seq && v.append(
|
|
798
|
+
return s && e.seq > 0 && i.lastReadByOthers >= e.seq && v.append(o("span", "ocw-seen", " · Seen")), f.append(v), a.append(f), a;
|
|
763
799
|
}
|
|
764
800
|
}
|
|
765
|
-
function
|
|
766
|
-
switch (
|
|
801
|
+
function Ke(t) {
|
|
802
|
+
switch (t) {
|
|
767
803
|
case "read":
|
|
768
804
|
return "✓✓";
|
|
769
805
|
case "delivered":
|
|
@@ -774,35 +810,44 @@ function ze(o) {
|
|
|
774
810
|
return "🕓";
|
|
775
811
|
}
|
|
776
812
|
}
|
|
777
|
-
const
|
|
778
|
-
function
|
|
779
|
-
return `relay-launcher::${
|
|
813
|
+
const H = /* @__PURE__ */ new WeakMap(), X = /* @__PURE__ */ new Map();
|
|
814
|
+
function ge(t) {
|
|
815
|
+
return `relay-launcher::${t.profileId}::${t.subjectId ?? ""}`;
|
|
816
|
+
}
|
|
817
|
+
let F = null;
|
|
818
|
+
function Ge() {
|
|
819
|
+
if (F && F.state !== "closed") return F;
|
|
820
|
+
try {
|
|
821
|
+
return F = new AudioContext(), F;
|
|
822
|
+
} catch {
|
|
823
|
+
return null;
|
|
824
|
+
}
|
|
780
825
|
}
|
|
781
|
-
function
|
|
826
|
+
function tt(t) {
|
|
782
827
|
var e;
|
|
783
|
-
(e =
|
|
828
|
+
(e = H.get(t)) == null || e.close(), H.delete(t);
|
|
784
829
|
}
|
|
785
|
-
function
|
|
786
|
-
var
|
|
787
|
-
|
|
788
|
-
const e =
|
|
830
|
+
function ot(t) {
|
|
831
|
+
var le, de, pe, he, ue;
|
|
832
|
+
H.has(t.el) && (H.get(t.el).close(), H.delete(t.el)), t.launcher && ((le = X.get(ge(t))) == null || le.close());
|
|
833
|
+
const e = je();
|
|
789
834
|
let i, s = !1;
|
|
790
|
-
const
|
|
791
|
-
let d = new
|
|
792
|
-
const
|
|
793
|
-
let
|
|
794
|
-
!
|
|
835
|
+
const r = t.token ?? t.userId ?? e, a = r !== e ? e : void 0, { wsUrl: f, httpBase: b } = Ae(t.url, t.apiUrl);
|
|
836
|
+
let d = new Me(r);
|
|
837
|
+
const h = t.subjectId ? `${r}::${t.subjectId}` : r, v = new Be(h);
|
|
838
|
+
let c, u = !1, l = null, E = null, g = null, w = null;
|
|
839
|
+
!t.launcher && !t.el.style.height && t.el.clientHeight === 0 && (t.el.style.width = t.el.style.width || "100%", t.el.style.height = "600px");
|
|
795
840
|
for (const n of v.load()) d.addOptimistic(n.clientMsgId, n.content);
|
|
796
|
-
let
|
|
797
|
-
if (
|
|
798
|
-
const p = (
|
|
799
|
-
|
|
800
|
-
const
|
|
801
|
-
|
|
841
|
+
let k = null, I = null, j = 0, C = !t.launcher;
|
|
842
|
+
if (t.launcher) {
|
|
843
|
+
const p = (t.position ?? "bottom-right").includes("right");
|
|
844
|
+
k = document.createElement("div"), k.style.cssText = `position:fixed;${p ? "right:20px" : "left:20px"};bottom:20px;z-index:9999;display:flex;flex-direction:column;align-items:${p ? "flex-end" : "flex-start"};gap:12px`;
|
|
845
|
+
const x = document.createElement("div"), L = typeof window < "u" && typeof window.matchMedia == "function" ? window.matchMedia("(max-width: 479px)") : null, V = (P) => {
|
|
846
|
+
t.el.classList.toggle("ocw-fs", P), x.style.cssText = P ? [
|
|
802
847
|
"position:fixed",
|
|
803
848
|
"inset:0",
|
|
804
849
|
"width:100%",
|
|
805
|
-
"height:
|
|
850
|
+
"height:100dvh",
|
|
806
851
|
"border-radius:0",
|
|
807
852
|
"overflow:hidden",
|
|
808
853
|
"box-shadow:none",
|
|
@@ -813,8 +858,8 @@ function Be(o) {
|
|
|
813
858
|
"opacity:0",
|
|
814
859
|
"z-index:9998"
|
|
815
860
|
].join(";") : [
|
|
816
|
-
"width:380px",
|
|
817
|
-
"height:600px",
|
|
861
|
+
"width:min(380px, calc(100vw - 40px))",
|
|
862
|
+
"height:min(600px, calc(100dvh - 108px))",
|
|
818
863
|
"border-radius:16px",
|
|
819
864
|
"overflow:hidden",
|
|
820
865
|
"box-shadow:0 8px 40px rgba(0,0,0,.18)",
|
|
@@ -827,117 +872,190 @@ function Be(o) {
|
|
|
827
872
|
"transform:scale(.95)"
|
|
828
873
|
].join(";");
|
|
829
874
|
};
|
|
830
|
-
|
|
831
|
-
const
|
|
832
|
-
|
|
833
|
-
const
|
|
834
|
-
|
|
875
|
+
V((L == null ? void 0 : L.matches) ?? !1);
|
|
876
|
+
const Y = (P) => V(P.matches);
|
|
877
|
+
L == null || L.addEventListener("change", Y), l = L, E = Y, t.el.style.cssText = "width:100%;height:100%;overflow:hidden", x.append(t.el);
|
|
878
|
+
const Q = '<svg viewBox="0 0 24 24" width="26" height="26" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>', Z = '<svg viewBox="0 0 24 24" width="22" height="22" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"/></svg>', M = document.createElement("button");
|
|
879
|
+
M.type = "button", M.style.cssText = [
|
|
835
880
|
"width:56px;height:56px;border-radius:50%",
|
|
836
|
-
`background:${
|
|
837
|
-
"color:#fff;border:none;
|
|
881
|
+
`background:${t.accent ?? "#4F63F5"}`,
|
|
882
|
+
"color:#fff;border:none;cursor:pointer",
|
|
838
883
|
"box-shadow:0 4px 16px rgba(0,0,0,.25)",
|
|
839
884
|
"position:relative;flex:none",
|
|
885
|
+
"display:flex;align-items:center;justify-content:center",
|
|
840
886
|
"transition:transform .15s"
|
|
841
|
-
].join(";"),
|
|
842
|
-
|
|
843
|
-
},
|
|
844
|
-
|
|
845
|
-
},
|
|
846
|
-
const
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
887
|
+
].join(";"), M.onmouseenter = () => {
|
|
888
|
+
M.style.transform = "scale(1.08)";
|
|
889
|
+
}, M.onmouseleave = () => {
|
|
890
|
+
M.style.transform = "scale(1)";
|
|
891
|
+
}, I = document.createElement("span"), I.style.cssText = "position:absolute;top:-4px;right:-4px;background:#ef4444;color:#fff;border-radius:50%;width:20px;height:20px;font-size:11px;font-weight:700;display:none;align-items:center;justify-content:center";
|
|
892
|
+
const K = () => {
|
|
893
|
+
M.innerHTML = C ? Z : Q, M.setAttribute("aria-label", C ? "Close chat" : "Open chat"), M.setAttribute("aria-expanded", String(C)), M.append(I);
|
|
894
|
+
};
|
|
895
|
+
K(), k.append(x, M), document.body.append(k);
|
|
896
|
+
const ee = `ocw-teaser-dismissed::${t.profileId}`, G = typeof t.launcherMessage == "string" ? { title: t.launcherMessage } : t.launcherMessage;
|
|
897
|
+
let z = null;
|
|
898
|
+
const Se = () => {
|
|
899
|
+
try {
|
|
900
|
+
return sessionStorage.getItem(ee) === "1";
|
|
901
|
+
} catch {
|
|
902
|
+
return !1;
|
|
903
|
+
}
|
|
904
|
+
}, ze = '<svg viewBox="0 0 24 24" width="15" height="15" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>', fe = () => {
|
|
905
|
+
const P = G != null && G.title ? G : d.launcherMessage ?? void 0;
|
|
906
|
+
if (!(!!(P != null && P.title) && !C && !Se())) {
|
|
907
|
+
z && (z.remove(), z = null);
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
if (z) return;
|
|
911
|
+
z = document.createElement("div"), z.setAttribute("role", "button"), z.setAttribute("tabindex", "0"), z.setAttribute("aria-label", P.title), z.style.cssText = [
|
|
912
|
+
"max-width:280px",
|
|
913
|
+
"background:#fff",
|
|
914
|
+
"border-radius:14px",
|
|
915
|
+
"box-shadow:0 6px 28px rgba(0,0,0,.16)",
|
|
916
|
+
"padding:14px 40px 14px 16px",
|
|
917
|
+
"position:relative",
|
|
918
|
+
"cursor:pointer",
|
|
919
|
+
"font-family:inherit",
|
|
920
|
+
`align-self:${p ? "flex-end" : "flex-start"}`,
|
|
921
|
+
"animation:ocw-teaser-in .22s ease-out"
|
|
922
|
+
].join(";");
|
|
923
|
+
const oe = document.createElement("div");
|
|
924
|
+
if (oe.textContent = P.title, oe.style.cssText = "font-size:15px;font-weight:600;color:#111;line-height:1.35", z.append(oe), P.subtitle) {
|
|
925
|
+
const D = document.createElement("div");
|
|
926
|
+
D.style.cssText = "display:flex;align-items:center;gap:6px;margin-top:6px;font-size:13px;color:#6b7280";
|
|
927
|
+
const ne = document.createElement("span");
|
|
928
|
+
ne.innerHTML = ze, ne.style.cssText = `color:${t.accent ?? "#4F63F5"};display:inline-flex`;
|
|
929
|
+
const be = document.createElement("span");
|
|
930
|
+
be.textContent = P.subtitle, D.append(ne, be), z.append(D);
|
|
931
|
+
}
|
|
932
|
+
const N = document.createElement("button");
|
|
933
|
+
N.type = "button", N.setAttribute("aria-label", "Dismiss"), N.innerHTML = '<svg viewBox="0 0 24 24" width="14" height="14" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M18 6 6 18M6 6l12 12" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"/></svg>', N.style.cssText = "position:absolute;top:8px;right:8px;width:24px;height:24px;border:none;border-radius:50%;background:#f3f4f6;color:#6b7280;cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0", N.addEventListener("click", (D) => {
|
|
934
|
+
D.stopPropagation();
|
|
935
|
+
try {
|
|
936
|
+
sessionStorage.setItem(ee, "1");
|
|
937
|
+
} catch {
|
|
938
|
+
}
|
|
939
|
+
z && (z.remove(), z = null);
|
|
940
|
+
}), z.append(N);
|
|
941
|
+
const we = () => {
|
|
942
|
+
C || (C = !0, te(!0), K(), j = 0, I && (I.style.display = "none"), z && (z.remove(), z = null));
|
|
943
|
+
};
|
|
944
|
+
z.addEventListener("click", we), z.addEventListener("keydown", (D) => {
|
|
945
|
+
(D.key === "Enter" || D.key === " ") && (D.preventDefault(), we());
|
|
946
|
+
}), k.insertBefore(z, M);
|
|
947
|
+
};
|
|
948
|
+
if (!document.getElementById("ocw-teaser-style")) {
|
|
949
|
+
const P = document.createElement("style");
|
|
950
|
+
P.id = "ocw-teaser-style", P.textContent = "@keyframes ocw-teaser-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}", document.head.append(P);
|
|
951
|
+
}
|
|
952
|
+
w = fe, fe();
|
|
953
|
+
const te = (P) => {
|
|
954
|
+
P ? (x.style.display = "flex", requestAnimationFrame(() => {
|
|
955
|
+
x.style.opacity = "1", x.style.transform = "scale(1)";
|
|
956
|
+
})) : (x.style.opacity = "0", x.style.transform = "scale(.95)", setTimeout(() => {
|
|
957
|
+
C || (x.style.display = "none");
|
|
851
958
|
}, 180));
|
|
852
959
|
};
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
960
|
+
M.addEventListener("click", () => {
|
|
961
|
+
if (C = !C, te(C), K(), C) {
|
|
962
|
+
j = 0, I && (I.style.display = "none");
|
|
963
|
+
try {
|
|
964
|
+
sessionStorage.setItem(ee, "1");
|
|
965
|
+
} catch {
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
w == null || w();
|
|
969
|
+
}), g = (P) => {
|
|
970
|
+
P.key === "Escape" && C && (C = !1, te(!1), K());
|
|
971
|
+
}, document.addEventListener("keydown", g);
|
|
858
972
|
}
|
|
859
|
-
const
|
|
860
|
-
|
|
973
|
+
const R = () => {
|
|
974
|
+
C || (j++, I && (I.textContent = String(j), I.style.display = "flex"));
|
|
861
975
|
}, A = () => {
|
|
862
976
|
try {
|
|
863
|
-
const n =
|
|
864
|
-
|
|
977
|
+
const n = Ge();
|
|
978
|
+
if (!n) return;
|
|
979
|
+
n.state === "suspended" && n.resume().catch(() => {
|
|
980
|
+
});
|
|
981
|
+
const p = n.createOscillator(), x = n.createGain();
|
|
982
|
+
p.connect(x), x.connect(n.destination), p.frequency.setValueAtTime(880, n.currentTime), p.frequency.exponentialRampToValueAtTime(440, n.currentTime + 0.15), x.gain.setValueAtTime(0.3, n.currentTime), x.gain.exponentialRampToValueAtTime(1e-3, n.currentTime + 0.3), p.start(), p.stop(n.currentTime + 0.3);
|
|
865
983
|
} catch {
|
|
866
984
|
}
|
|
867
|
-
},
|
|
868
|
-
for (;
|
|
869
|
-
const p =
|
|
870
|
-
v.add({ clientMsgId: p.clientMsgId, content: p.content, ts: Date.now() }),
|
|
985
|
+
}, O = [], U = (n) => {
|
|
986
|
+
for (; O.length; ) {
|
|
987
|
+
const p = O.shift();
|
|
988
|
+
v.add({ clientMsgId: p.clientMsgId, content: p.content, ts: Date.now() }), T.send({ type: "send", conversationId: n, clientMsgId: p.clientMsgId, content: p.content });
|
|
871
989
|
}
|
|
872
990
|
};
|
|
873
|
-
let
|
|
874
|
-
const
|
|
875
|
-
let
|
|
876
|
-
const
|
|
877
|
-
let
|
|
878
|
-
const
|
|
879
|
-
|
|
880
|
-
|
|
991
|
+
let T;
|
|
992
|
+
const B = new qe(`ocw-e2e-${t.profileId}`);
|
|
993
|
+
let m = !1;
|
|
994
|
+
const S = [], q = [];
|
|
995
|
+
let se = !1;
|
|
996
|
+
const J = (n, p) => {
|
|
997
|
+
B.sealText(p).then((x) => {
|
|
998
|
+
c && T.send({ type: "send", conversationId: c, clientMsgId: n, content: x });
|
|
881
999
|
});
|
|
882
|
-
},
|
|
883
|
-
|
|
884
|
-
|
|
1000
|
+
}, ye = (n, p, x) => {
|
|
1001
|
+
B.sealText(p, x).then((L) => {
|
|
1002
|
+
c && T.send({ type: "send", conversationId: c, clientMsgId: n, content: L });
|
|
885
1003
|
});
|
|
886
|
-
},
|
|
887
|
-
for (;
|
|
888
|
-
const n =
|
|
889
|
-
|
|
1004
|
+
}, ve = () => {
|
|
1005
|
+
for (; S.length; ) {
|
|
1006
|
+
const n = S.shift();
|
|
1007
|
+
J(n.clientMsgId, n.text);
|
|
890
1008
|
}
|
|
891
|
-
for (;
|
|
892
|
-
const n =
|
|
893
|
-
|
|
1009
|
+
for (; q.length; ) {
|
|
1010
|
+
const n = q.shift();
|
|
1011
|
+
J(n.clientMsgId, n.text);
|
|
894
1012
|
}
|
|
895
|
-
},
|
|
896
|
-
|
|
897
|
-
},
|
|
898
|
-
|
|
899
|
-
const
|
|
1013
|
+
}, ke = (n) => {
|
|
1014
|
+
T.send({ type: "fetchPrekey", targetUserId: n });
|
|
1015
|
+
}, Ce = t.i18n ?? {}, Te = ["ar", "he", "fa", "ur"], Ee = typeof navigator < "u" ? (navigator.language ?? "").slice(0, 2).toLowerCase() : "";
|
|
1016
|
+
Te.includes(Ee) && !t.el.dir && (t.el.dir = "rtl", t.el.style.fontFamily = t.el.style.fontFamily || "Tahoma,Arial,system-ui,sans-serif");
|
|
1017
|
+
const re = new He(), ae = `oc_prechat_${t.profileId}_${r.slice(-8)}`, $ = new Ye(t.el, r, {
|
|
900
1018
|
onSend(n) {
|
|
901
|
-
const p = `cm_${Math.random().toString(36).slice(2)}`,
|
|
902
|
-
d.addOptimistic(p,
|
|
1019
|
+
const p = `cm_${Math.random().toString(36).slice(2)}`, x = { kind: "text", text: n };
|
|
1020
|
+
d.addOptimistic(p, x), $.render(d), d.e2e ? B.ready ? J(p, n) : se ? q.push({ clientMsgId: p, text: n }) : (S.push({ clientMsgId: p, text: n }), d.assignedAgentId && ke(d.assignedAgentId)) : c ? (v.add({ clientMsgId: p, content: x, ts: Date.now() }), T.send({ type: "send", conversationId: c, clientMsgId: p, content: x })) : O.push({ clientMsgId: p, content: x });
|
|
903
1021
|
},
|
|
904
1022
|
async onAttach(n) {
|
|
905
|
-
if (!
|
|
906
|
-
const p = `${b}/upload?name=${encodeURIComponent(n.name)}`,
|
|
907
|
-
d.addOptimistic(
|
|
1023
|
+
if (!c) return;
|
|
1024
|
+
const p = `${b}/upload?name=${encodeURIComponent(n.name)}`, x = `cm_${Math.random().toString(36).slice(2)}`;
|
|
1025
|
+
d.addOptimistic(x, { kind: "text", text: `📎 Uploading ${n.name}…` }), $.render(d);
|
|
908
1026
|
try {
|
|
909
|
-
const
|
|
1027
|
+
const L = await fetch(p, {
|
|
910
1028
|
method: "POST",
|
|
911
1029
|
// Use the resolved connection token (a signed JWT, an explicit userId,
|
|
912
1030
|
// or the anonymous persistent uid) — NOT just opts.token. The server
|
|
913
1031
|
// requires an Authorization header, and the verifier accepts an
|
|
914
1032
|
// anonymous id as a guest; keying off opts.token alone meant anonymous
|
|
915
1033
|
// visitors (the common case) sent no auth and every upload 401'd.
|
|
916
|
-
headers: { "content-type": n.type, authorization: `Bearer ${
|
|
1034
|
+
headers: { "content-type": n.type, authorization: `Bearer ${r}` },
|
|
917
1035
|
body: n
|
|
918
1036
|
});
|
|
919
|
-
if (!
|
|
920
|
-
const { url:
|
|
921
|
-
|
|
922
|
-
} catch (
|
|
923
|
-
d.addOptimistic(
|
|
1037
|
+
if (!L.ok) throw new Error(`Upload failed: ${L.status}`);
|
|
1038
|
+
const { url: V, name: Y, mime: Q, size: Z } = await L.json();
|
|
1039
|
+
T.send({ type: "send", conversationId: c, clientMsgId: x, content: { kind: "attachment", url: V, name: Y, mime: Q, size: Z } });
|
|
1040
|
+
} catch (L) {
|
|
1041
|
+
d.addOptimistic(x, { kind: "text", text: `⚠️ Upload failed: ${L.message}` }), $.render(d);
|
|
924
1042
|
}
|
|
925
1043
|
},
|
|
926
1044
|
onInvoke(n, p) {
|
|
927
|
-
|
|
1045
|
+
c && T.send({ type: "invoke", conversationId: c, actionId: n, clientInvokeId: `iv_${Math.random().toString(36).slice(2)}`, ...p ? { inputs: p } : {} });
|
|
928
1046
|
},
|
|
929
1047
|
onTyping(n, p) {
|
|
930
|
-
|
|
1048
|
+
c && T.send({ type: "typing", conversationId: c, isTyping: n, ...p ? { preview: p } : {} });
|
|
931
1049
|
},
|
|
932
1050
|
onPreChat(n) {
|
|
933
1051
|
try {
|
|
934
|
-
localStorage.setItem(
|
|
1052
|
+
localStorage.setItem(ae, "1");
|
|
935
1053
|
} catch {
|
|
936
1054
|
}
|
|
937
|
-
|
|
1055
|
+
T.send({
|
|
938
1056
|
type: "open",
|
|
939
|
-
profileId:
|
|
940
|
-
...
|
|
1057
|
+
profileId: t.profileId,
|
|
1058
|
+
...t.subjectId ? { subjectId: t.subjectId } : {},
|
|
941
1059
|
userInfo: {
|
|
942
1060
|
...n.name ? { name: n.name } : {},
|
|
943
1061
|
...n.email ? { email: n.email } : {},
|
|
@@ -948,168 +1066,168 @@ function Be(o) {
|
|
|
948
1066
|
}
|
|
949
1067
|
});
|
|
950
1068
|
const p = n.callback ? `📞 Call-back requested${n.phone ? `: ${n.phone}` : ""}${n.topic ? ` — ${n.topic}` : ""}` : n.topic ? `Topic: ${n.topic}` : "";
|
|
951
|
-
p &&
|
|
1069
|
+
p && c && !d.e2e && T.send({ type: "send", conversationId: c, clientMsgId: `pc_${Math.random().toString(36).slice(2, 12)}`, content: { kind: "text", text: p } });
|
|
952
1070
|
},
|
|
953
1071
|
onDeflectQuery(n) {
|
|
954
1072
|
if (s) return;
|
|
955
1073
|
clearTimeout(i);
|
|
956
1074
|
const p = n.trim();
|
|
957
1075
|
if (p.length < 3) {
|
|
958
|
-
|
|
1076
|
+
$.hideDeflection();
|
|
959
1077
|
return;
|
|
960
1078
|
}
|
|
961
1079
|
i = setTimeout(() => {
|
|
962
|
-
fetch(`${b}/kb/search?profileId=${encodeURIComponent(
|
|
1080
|
+
fetch(`${b}/kb/search?profileId=${encodeURIComponent(t.profileId)}&q=${encodeURIComponent(p.slice(0, 200))}`).then((x) => x.ok ? x.json() : { articles: [] }).then((x) => $.showDeflection(x.articles ?? [])).catch(() => $.hideDeflection());
|
|
963
1081
|
}, 350);
|
|
964
1082
|
},
|
|
965
1083
|
onReadUpTo(n) {
|
|
966
|
-
|
|
1084
|
+
c && T.send({ type: "read", conversationId: c, seq: n });
|
|
967
1085
|
},
|
|
968
1086
|
onLoadMore() {
|
|
969
|
-
if (!
|
|
1087
|
+
if (!c || !d.e2e) return;
|
|
970
1088
|
const n = d.messages()[0];
|
|
971
|
-
n &&
|
|
1089
|
+
n && T.send({ type: "history", conversationId: c, beforeSeq: n.seq, limit: 20 });
|
|
972
1090
|
},
|
|
973
1091
|
onEdit(n, p) {
|
|
974
|
-
|
|
1092
|
+
c && T.send({ type: "edit", conversationId: c, messageId: n, content: { kind: "text", text: p } });
|
|
975
1093
|
},
|
|
976
1094
|
onDelete(n) {
|
|
977
|
-
|
|
1095
|
+
c && T.send({ type: "delete", conversationId: c, messageId: n });
|
|
978
1096
|
},
|
|
979
|
-
onReact(n, p,
|
|
980
|
-
|
|
1097
|
+
onReact(n, p, x) {
|
|
1098
|
+
c && T.send({ type: "react", conversationId: c, messageId: n, emoji: p, remove: x });
|
|
981
1099
|
},
|
|
982
1100
|
onCsat(n) {
|
|
983
|
-
|
|
1101
|
+
c && fetch(`${b}/conversations/${c}/csat`, {
|
|
984
1102
|
method: "POST",
|
|
985
|
-
headers: { "Content-Type": "application/json", Authorization: `Bearer ${
|
|
1103
|
+
headers: { "Content-Type": "application/json", Authorization: `Bearer ${r}` },
|
|
986
1104
|
body: JSON.stringify({ score: n })
|
|
987
1105
|
}).catch(() => {
|
|
988
1106
|
});
|
|
989
1107
|
},
|
|
990
1108
|
onAnnotate(n) {
|
|
991
|
-
|
|
1109
|
+
c && T.send({ type: "annotate", conversationId: c, stroke: n });
|
|
992
1110
|
},
|
|
993
1111
|
onAnnotateClear() {
|
|
994
|
-
|
|
1112
|
+
c && T.send({ type: "annotate_clear", conversationId: c });
|
|
995
1113
|
},
|
|
996
|
-
...
|
|
1114
|
+
...t.translateLang ? {
|
|
997
1115
|
async onTranslate(n) {
|
|
998
1116
|
try {
|
|
999
1117
|
const p = await fetch(`${b}/translate`, {
|
|
1000
1118
|
method: "POST",
|
|
1001
|
-
headers: { "content-type": "application/json", authorization: `Bearer ${
|
|
1002
|
-
body: JSON.stringify({ text: n, targetLang:
|
|
1119
|
+
headers: { "content-type": "application/json", authorization: `Bearer ${r}` },
|
|
1120
|
+
body: JSON.stringify({ text: n, targetLang: t.translateLang })
|
|
1003
1121
|
});
|
|
1004
1122
|
if (!p.ok) return null;
|
|
1005
|
-
const { translated:
|
|
1006
|
-
return
|
|
1123
|
+
const { translated: x } = await p.json();
|
|
1124
|
+
return x;
|
|
1007
1125
|
} catch {
|
|
1008
1126
|
return null;
|
|
1009
1127
|
}
|
|
1010
1128
|
}
|
|
1011
1129
|
} : {},
|
|
1012
|
-
...
|
|
1130
|
+
...t.onBack ? { onBack: t.onBack } : {}
|
|
1013
1131
|
}, {
|
|
1014
|
-
...
|
|
1015
|
-
...
|
|
1016
|
-
...
|
|
1017
|
-
...(
|
|
1018
|
-
i18n:
|
|
1132
|
+
...t.subject ? { subject: t.subject } : {},
|
|
1133
|
+
...t.quickReplies ? { quickReplies: t.quickReplies } : {},
|
|
1134
|
+
...t.accent ? { accent: t.accent } : {},
|
|
1135
|
+
...(de = t.user) != null && de.name || (pe = t.user) != null && pe.avatar ? { userInfo: { ...t.user.name ? { name: t.user.name } : {}, ...t.user.avatar ? { avatar: t.user.avatar } : {} } } : {},
|
|
1136
|
+
i18n: Ce
|
|
1019
1137
|
});
|
|
1020
1138
|
try {
|
|
1021
|
-
localStorage.getItem(
|
|
1139
|
+
localStorage.getItem(ae) && $.completePreChat();
|
|
1022
1140
|
} catch {
|
|
1023
1141
|
}
|
|
1024
|
-
const
|
|
1025
|
-
...
|
|
1026
|
-
...
|
|
1027
|
-
...
|
|
1028
|
-
...
|
|
1029
|
-
} : void 0,
|
|
1142
|
+
const ce = t.user && (t.user.name || t.user.email || t.user.avatar || t.user.meta) ? {
|
|
1143
|
+
...t.user.name ? { name: t.user.name } : {},
|
|
1144
|
+
...t.user.email ? { email: t.user.email } : {},
|
|
1145
|
+
...t.user.avatar ? { avatar: t.user.avatar } : {},
|
|
1146
|
+
...t.user.meta ? { meta: t.user.meta } : {}
|
|
1147
|
+
} : void 0, Ie = {
|
|
1030
1148
|
type: "open",
|
|
1031
|
-
profileId:
|
|
1149
|
+
profileId: t.profileId,
|
|
1032
1150
|
// Direct conversations use the kind/peerId pair; the dm:… subject key is
|
|
1033
1151
|
// server-derived and owner-keyed, so passing it as subjectId from the
|
|
1034
1152
|
// NON-owner side would find-or-create a junk duplicate thread.
|
|
1035
|
-
...
|
|
1036
|
-
...
|
|
1037
|
-
...
|
|
1153
|
+
...t.kind === "direct" && t.peerId ? { kind: "direct", peerId: t.peerId } : t.subjectId ? { subjectId: t.subjectId } : {},
|
|
1154
|
+
...a ? { linkFrom: a } : {},
|
|
1155
|
+
...ce ? { userInfo: ce } : {},
|
|
1038
1156
|
...typeof location < "u" ? { pageUrl: location.href } : {},
|
|
1039
1157
|
...typeof document < "u" && document.title ? { pageTitle: document.title } : {},
|
|
1040
1158
|
// Pass subject display info so the server can persist it to the Subject record.
|
|
1041
1159
|
// This is how listingTitle and listingMeta get saved without a separate API call.
|
|
1042
|
-
...(
|
|
1043
|
-
...(
|
|
1160
|
+
...(he = t.subject) != null && he.title ? { subjectTitle: t.subject.title } : {},
|
|
1161
|
+
...(ue = t.subject) != null && ue.subtitle ? { subjectMeta: t.subject.subtitle } : {}
|
|
1044
1162
|
};
|
|
1045
|
-
|
|
1046
|
-
...
|
|
1163
|
+
T = new Re({
|
|
1164
|
+
...t.refreshToken ? { refreshToken: t.refreshToken } : {},
|
|
1047
1165
|
url: f,
|
|
1048
|
-
token:
|
|
1049
|
-
open:
|
|
1166
|
+
token: r,
|
|
1167
|
+
open: Ie,
|
|
1050
1168
|
getCursor: () => d.highestSeq(),
|
|
1051
|
-
onStatusChange: (n, p) =>
|
|
1169
|
+
onStatusChange: (n, p) => $.setConnStatus(n, p),
|
|
1052
1170
|
onFrame(n) {
|
|
1053
|
-
if (
|
|
1054
|
-
if (
|
|
1171
|
+
if (re.apply(n), n.type === "opened") {
|
|
1172
|
+
if (c = n.conversation.id, !u) {
|
|
1055
1173
|
u = !0;
|
|
1056
1174
|
for (const p of v.load())
|
|
1057
|
-
|
|
1175
|
+
T.send({ type: "send", conversationId: c, clientMsgId: p.clientMsgId, content: p.content });
|
|
1058
1176
|
}
|
|
1059
|
-
|
|
1177
|
+
$e(f, r, c, d, $, b), O.length && U(c);
|
|
1060
1178
|
}
|
|
1061
1179
|
if (n.type === "ack" && v.remove(n.clientMsgId), n.type === "prekeyBundle") {
|
|
1062
|
-
n.bundle && (
|
|
1063
|
-
const
|
|
1064
|
-
for (const
|
|
1065
|
-
|
|
1180
|
+
n.bundle && (se = !0, B.x3dhSendTo(n.bundle).then((p) => {
|
|
1181
|
+
const x = [...S.splice(0), ...q.splice(0)];
|
|
1182
|
+
for (const L of x) ye(L.clientMsgId, L.text, p);
|
|
1183
|
+
$.render(d);
|
|
1066
1184
|
}));
|
|
1067
1185
|
return;
|
|
1068
1186
|
}
|
|
1069
1187
|
if (n.type === "message" && d.e2e) {
|
|
1070
|
-
const p =
|
|
1071
|
-
if (p && !
|
|
1072
|
-
|
|
1073
|
-
await
|
|
1188
|
+
const p = Oe(n.message.content);
|
|
1189
|
+
if (p && !B.ready) {
|
|
1190
|
+
B.x3dhReceiveFrom(p.x3dhIK, p.x3dhEK, p.x3dhSPK).then(async () => {
|
|
1191
|
+
await B.openFrame(n), d.apply(n), $.render(d);
|
|
1074
1192
|
});
|
|
1075
1193
|
return;
|
|
1076
1194
|
}
|
|
1077
1195
|
}
|
|
1078
1196
|
if (n.type === "peerkey") {
|
|
1079
|
-
|
|
1080
|
-
|
|
1197
|
+
B.onPeerKey(n.key).then(() => {
|
|
1198
|
+
ve(), $.render(d);
|
|
1081
1199
|
});
|
|
1082
1200
|
return;
|
|
1083
1201
|
}
|
|
1084
1202
|
(async () => {
|
|
1085
|
-
if (d.e2e && await
|
|
1086
|
-
|
|
1087
|
-
const p = await
|
|
1088
|
-
|
|
1089
|
-
const
|
|
1090
|
-
|
|
1203
|
+
if (d.e2e && await B.openFrame(n), d.apply(n), n.type === "manifest" && (w == null || w()), n.type === "message" && n.message.senderId !== r && !n.message.internal && (R(), A()), d.e2e && c && !m) {
|
|
1204
|
+
m = !0;
|
|
1205
|
+
const p = await B.initX3DH();
|
|
1206
|
+
T.send({ type: "uploadPrekeys", ...p });
|
|
1207
|
+
const x = await B.begin();
|
|
1208
|
+
T.send({ type: "pubkey", conversationId: c, key: x });
|
|
1091
1209
|
}
|
|
1092
|
-
|
|
1210
|
+
$.render(d);
|
|
1093
1211
|
})();
|
|
1094
1212
|
}
|
|
1095
|
-
}),
|
|
1096
|
-
const
|
|
1097
|
-
s = !0, clearTimeout(i),
|
|
1213
|
+
}), T.connect(), $.render(d);
|
|
1214
|
+
const _ = t.launcher ? ge(t) : null, W = { close: () => {
|
|
1215
|
+
s = !0, clearTimeout(i), T.close(), k == null || k.remove(), $.destroy(), re.destroy(), l && E && l.removeEventListener("change", E), g && (document.removeEventListener("keydown", g), g = null), H.delete(t.el), _ && X.get(_) === W && X.delete(_);
|
|
1098
1216
|
} };
|
|
1099
|
-
return
|
|
1217
|
+
return H.set(t.el, W), _ && X.set(_, W), W;
|
|
1100
1218
|
}
|
|
1101
1219
|
export {
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1220
|
+
Me as ChatStore,
|
|
1221
|
+
Re as ConnectionManager,
|
|
1222
|
+
qe as E2ESession,
|
|
1223
|
+
Be as PersistentOutbox,
|
|
1224
|
+
Ye as Renderer,
|
|
1225
|
+
at as asConversationId,
|
|
1226
|
+
Oe as extractX3DHInit,
|
|
1227
|
+
st as httpBaseFromWsUrl,
|
|
1228
|
+
ot as mount,
|
|
1229
|
+
Ae as resolveRelayUrls,
|
|
1230
|
+
$e as restoreHistory,
|
|
1231
|
+
tt as unmount
|
|
1114
1232
|
};
|
|
1115
1233
|
//# sourceMappingURL=index.js.map
|