@lightworkai.official/debug-capture 0.19.9 → 0.19.10
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 +3 -2
- package/dist/debug-capture.js +17 -16
- package/dist/index.mjs +22 -21
- package/dist/ui/chatBubble.d.ts +13 -6
- package/package.json +1 -1
- package/src/ui/chatBubble.ts +56 -25
package/dist/ui/chatBubble.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { type PlaceRule } from "./bubblePlace";
|
|
2
|
+
/**
|
|
3
|
+
* The desk's size for it, px (0.19.10; the owner, 11-02: "make it smaller or bigger as a config") — the desk offers
|
|
4
|
+
* 44 to 72; anything else it might say is brought within reach of a finger and of the corner. Pure.
|
|
5
|
+
*/
|
|
6
|
+
export declare function bubbleSize(v: unknown): number;
|
|
2
7
|
/** The panel's address: the support host's page, told the realm, signing in by hand-off (no token in the address). */
|
|
3
8
|
export declare function supportFrameUrl(host: string, realmKey: string): string;
|
|
4
9
|
/** Where the panel's เปิดในระบบแจ้งปัญหา may land: the person's chat or their เรื่อง — anything else, their chat. Pure. */
|
|
@@ -9,9 +14,9 @@ export declare function supportFaceUrl(host: string): string;
|
|
|
9
14
|
* How far the call's card and frame rise from their own 16px so they clear the bubble — its offset, its size and the
|
|
10
15
|
* gap above it (0.19.1: 0.19.0 assumed the bubble at the corner, and a raised one sat under a ringing call). Pure.
|
|
11
16
|
*/
|
|
12
|
-
export declare function chatLift(bubbleY: number): number;
|
|
17
|
+
export declare function chatLift(bubbleY: number, s?: number): number;
|
|
13
18
|
/** The panel above the bubble, never past the top of the window — its height for the bubble's offset (0.19.1). Pure. */
|
|
14
|
-
export declare function panelHeight(bubbleY: number): string;
|
|
19
|
+
export declare function panelHeight(bubbleY: number, s?: number): string;
|
|
15
20
|
export interface BubbleSpot {
|
|
16
21
|
side: "right" | "left";
|
|
17
22
|
/** In from that side, px. */
|
|
@@ -23,16 +28,16 @@ export interface BubbleSpot {
|
|
|
23
28
|
export declare function settleBubble(px: number, py: number, view: {
|
|
24
29
|
w: number;
|
|
25
30
|
h: number;
|
|
26
|
-
}, inset: number): BubbleSpot;
|
|
31
|
+
}, inset: number, s?: number): BubbleSpot;
|
|
27
32
|
/** A height that keeps the whole bubble on screen. Pure. */
|
|
28
|
-
export declare function clampBubbleY(y: number, viewH: number): number;
|
|
33
|
+
export declare function clampBubbleY(y: number, viewH: number, s?: number): number;
|
|
29
34
|
/** How far the call's card rises to clear the bubble: only a bubble on its side, low enough to meet it. Pure. */
|
|
30
|
-
export declare function liftFor(spot: BubbleSpot): number;
|
|
35
|
+
export declare function liftFor(spot: BubbleSpot, s?: number): number;
|
|
31
36
|
/**
|
|
32
37
|
* The panel by the bubble, where it was not dragged: above it when the room above is enough (or more than below),
|
|
33
38
|
* else below it — its own height, never past the window. Pure.
|
|
34
39
|
*/
|
|
35
|
-
export declare function anchorPanel(spot: BubbleSpot, viewH: number): {
|
|
40
|
+
export declare function anchorPanel(spot: BubbleSpot, viewH: number, s?: number): {
|
|
36
41
|
bottom?: number;
|
|
37
42
|
top?: number;
|
|
38
43
|
height: number;
|
|
@@ -75,6 +80,8 @@ export interface DeskLook {
|
|
|
75
80
|
avoid?: boolean;
|
|
76
81
|
/** A page's own place (0.19.6): hidden there, or started in a corner at a height — the desk's rules. */
|
|
77
82
|
places?: PlaceRule[];
|
|
83
|
+
/** ขนาดปุ่ม, px (0.19.10) — 56 when the desk does not say. */
|
|
84
|
+
size?: number;
|
|
78
85
|
}
|
|
79
86
|
/** The face's address for a desk's look: its own path on the support host, the shipped one, or none (the glyph). Pure. */
|
|
80
87
|
export declare function lookFaceUrl(host: string, look: DeskLook | null): string | null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lightworkai.official/debug-capture",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.10",
|
|
4
4
|
"description": "Report-a-problem widget: rolling network/console/action capture, optional rrweb session replay, annotated screenshot, and submission to a Lightwork Support host",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./dist/index.mjs",
|
package/src/ui/chatBubble.ts
CHANGED
|
@@ -25,15 +25,25 @@ import { strings } from "./strings";
|
|
|
25
25
|
const HOST_TAG = "lw-support-chat";
|
|
26
26
|
const FRAME = "lw-support-frame";
|
|
27
27
|
const HOST = "lw-support-host";
|
|
28
|
+
/** The button's size until the desk says its own (ปุ่มแชท › ขนาดปุ่ม, 0.19.10). */
|
|
28
29
|
const SIZE = 56;
|
|
29
30
|
const GAP = 12;
|
|
31
|
+
/**
|
|
32
|
+
* The desk's size for it, px (0.19.10; the owner, 11-02: "make it smaller or bigger as a config") — the desk offers
|
|
33
|
+
* 44 to 72; anything else it might say is brought within reach of a finger and of the corner. Pure.
|
|
34
|
+
*/
|
|
35
|
+
export function bubbleSize(v: unknown): number {
|
|
36
|
+
return typeof v === "number" && Number.isFinite(v) ? Math.round(Math.min(Math.max(v, 32), 96)) : SIZE;
|
|
37
|
+
}
|
|
38
|
+
/** Its size now — the desk's, once its look is read. */
|
|
39
|
+
let size = SIZE;
|
|
30
40
|
|
|
31
41
|
const ICON = `<svg viewBox="0 0 24 24" width="26" height="26" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M7.9 20A9 9 0 1 0 4 16.1L2 22Z"/></svg>`;
|
|
32
42
|
|
|
33
43
|
const CSS = `
|
|
34
44
|
:host { all: initial; }
|
|
35
45
|
.bubble {
|
|
36
|
-
position: fixed; z-index: 2147483000; width: ${SIZE}px; height: ${SIZE}px; border-radius: 50%;
|
|
46
|
+
position: fixed; z-index: 2147483000; width: var(--lw-chat-size, ${SIZE}px); height: var(--lw-chat-size, ${SIZE}px); border-radius: 50%;
|
|
37
47
|
display: grid; place-items: center; border: 0; cursor: pointer; padding: 0;
|
|
38
48
|
background: var(--lw-chat-color, #00468f); color: #fff; box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.3), 0 4px 10px -4px rgba(0, 0, 0, 0.2);
|
|
39
49
|
transition: transform 150ms ease, background 150ms ease;
|
|
@@ -43,6 +53,7 @@ const CSS = `
|
|
|
43
53
|
.bubble { touch-action: none; }
|
|
44
54
|
.bubble.dragging { cursor: grabbing; transform: scale(1.06); transition: none; box-shadow: 0 18px 35px -8px rgba(0, 0, 0, 0.4); }
|
|
45
55
|
.bubble:focus-visible { outline: 3px solid rgba(0, 70, 143, 0.35); outline-offset: 3px; }
|
|
56
|
+
.bubble > svg { width: calc(var(--lw-chat-size, ${SIZE}px) * 0.46); height: calc(var(--lw-chat-size, ${SIZE}px) * 0.46); }
|
|
46
57
|
.face { display: none; width: 100%; height: 100%; border-radius: 50%; object-fit: cover; pointer-events: none; user-select: none; -webkit-user-drag: none; }
|
|
47
58
|
.bubble.has-face, .bubble.has-face:hover { background: #fff; }
|
|
48
59
|
.has-face .face { display: block; }
|
|
@@ -64,7 +75,7 @@ const CSS = `
|
|
|
64
75
|
content: ""; position: absolute; top: 50%; right: -4px; width: 10px; height: 10px; background: #fff; border-radius: 2px;
|
|
65
76
|
transform: translateY(-50%) rotate(45deg); box-shadow: 1px -1px 0 rgba(0, 0, 0, 0.04);
|
|
66
77
|
}
|
|
67
|
-
.label .text { display: block; max-width: min(240px, calc(100vw - ${SIZE
|
|
78
|
+
.label .text { display: block; max-width: min(240px, calc(100vw - var(--lw-chat-size, ${SIZE}px) - 64px)); overflow: hidden; text-overflow: ellipsis; }
|
|
68
79
|
.at-left .label { right: auto; left: calc(100% + 12px); transform: translate(-4px, -50%); }
|
|
69
80
|
.at-left .label::after { right: auto; left: -4px; }
|
|
70
81
|
.new .label { color: var(--lw-chat-color, #00468f); }
|
|
@@ -72,7 +83,7 @@ const CSS = `
|
|
|
72
83
|
@media (hover: hover) { .bubble:hover .label { opacity: 1; visibility: visible; pointer-events: auto; transform: translate(0, -50%); } }
|
|
73
84
|
.unlabelled .label, .bubble.dragging .label, .open .label { display: none; }
|
|
74
85
|
.panel {
|
|
75
|
-
position: fixed; z-index: 2147483001; width: min(380px, calc(100vw - 32px)); height: min(640px, calc(100vh - ${SIZE
|
|
86
|
+
position: fixed; z-index: 2147483001; width: min(380px, calc(100vw - 32px)); height: min(640px, calc(100vh - var(--lw-chat-size, ${SIZE}px) - ${GAP + 32}px));
|
|
76
87
|
border-radius: 20px; overflow: hidden; background: #fff; border: 1px solid rgba(15, 23, 42, 0.08);
|
|
77
88
|
box-shadow: 0 28px 64px -16px rgba(15, 23, 42, 0.3), 0 10px 24px -10px rgba(15, 23, 42, 0.14);
|
|
78
89
|
animation: in 180ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
@@ -126,12 +137,12 @@ export function supportFaceUrl(host: string): string {
|
|
|
126
137
|
* How far the call's card and frame rise from their own 16px so they clear the bubble — its offset, its size and the
|
|
127
138
|
* gap above it (0.19.1: 0.19.0 assumed the bubble at the corner, and a raised one sat under a ringing call). Pure.
|
|
128
139
|
*/
|
|
129
|
-
export function chatLift(bubbleY: number): number {
|
|
130
|
-
return bubbleY +
|
|
140
|
+
export function chatLift(bubbleY: number, s = SIZE): number {
|
|
141
|
+
return bubbleY + s + GAP - 16;
|
|
131
142
|
}
|
|
132
143
|
/** The panel above the bubble, never past the top of the window — its height for the bubble's offset (0.19.1). Pure. */
|
|
133
|
-
export function panelHeight(bubbleY: number): string {
|
|
134
|
-
return `min(640px, calc(100vh - ${bubbleY +
|
|
144
|
+
export function panelHeight(bubbleY: number, s = SIZE): string {
|
|
145
|
+
return `min(640px, calc(100vh - ${bubbleY + s + GAP + 16}px))`;
|
|
135
146
|
}
|
|
136
147
|
|
|
137
148
|
/*
|
|
@@ -151,26 +162,26 @@ const MARGIN = 8;
|
|
|
151
162
|
/** The ring's card is ~180px tall at the corner: a bubble above that leaves it there. */
|
|
152
163
|
const RING_ZONE = 200;
|
|
153
164
|
/** Let go at (px, py), its centre: the nearer side, the height it was dropped at — inside the window. Pure. */
|
|
154
|
-
export function settleBubble(px: number, py: number, view: { w: number; h: number }, inset: number): BubbleSpot {
|
|
165
|
+
export function settleBubble(px: number, py: number, view: { w: number; h: number }, inset: number, s = SIZE): BubbleSpot {
|
|
155
166
|
const side = px < view.w / 2 ? "left" : "right";
|
|
156
|
-
return { side, x: inset, y: clampBubbleY(view.h - py -
|
|
167
|
+
return { side, x: inset, y: clampBubbleY(view.h - py - s / 2, view.h, s) };
|
|
157
168
|
}
|
|
158
169
|
/** A height that keeps the whole bubble on screen. Pure. */
|
|
159
|
-
export function clampBubbleY(y: number, viewH: number): number {
|
|
160
|
-
return Math.round(Math.min(Math.max(y, MARGIN), Math.max(MARGIN, viewH -
|
|
170
|
+
export function clampBubbleY(y: number, viewH: number, s = SIZE): number {
|
|
171
|
+
return Math.round(Math.min(Math.max(y, MARGIN), Math.max(MARGIN, viewH - s - MARGIN)));
|
|
161
172
|
}
|
|
162
173
|
/** How far the call's card rises to clear the bubble: only a bubble on its side, low enough to meet it. Pure. */
|
|
163
|
-
export function liftFor(spot: BubbleSpot): number {
|
|
164
|
-
return spot.side === "right" && spot.y < RING_ZONE ? chatLift(spot.y) : 0;
|
|
174
|
+
export function liftFor(spot: BubbleSpot, s = SIZE): number {
|
|
175
|
+
return spot.side === "right" && spot.y < RING_ZONE ? chatLift(spot.y, s) : 0;
|
|
165
176
|
}
|
|
166
177
|
/**
|
|
167
178
|
* The panel by the bubble, where it was not dragged: above it when the room above is enough (or more than below),
|
|
168
179
|
* else below it — its own height, never past the window. Pure.
|
|
169
180
|
*/
|
|
170
|
-
export function anchorPanel(spot: BubbleSpot, viewH: number): { bottom?: number; top?: number; height: number } {
|
|
171
|
-
const above = viewH - (spot.y +
|
|
181
|
+
export function anchorPanel(spot: BubbleSpot, viewH: number, s = SIZE): { bottom?: number; top?: number; height: number } {
|
|
182
|
+
const above = viewH - (spot.y + s + GAP) - 16;
|
|
172
183
|
const below = spot.y - GAP - 16;
|
|
173
|
-
if (above >= 420 || above >= below) return { bottom: spot.y +
|
|
184
|
+
if (above >= 420 || above >= below) return { bottom: spot.y + s + GAP, height: Math.max(240, Math.min(640, above)) };
|
|
174
185
|
return { top: viewH - spot.y + GAP, height: Math.max(240, Math.min(640, below)) };
|
|
175
186
|
}
|
|
176
187
|
/** A dragged panel's top-left, inside the window by the margin. Pure. */
|
|
@@ -233,6 +244,8 @@ export interface DeskLook {
|
|
|
233
244
|
avoid?: boolean;
|
|
234
245
|
/** A page's own place (0.19.6): hidden there, or started in a corner at a height — the desk's rules. */
|
|
235
246
|
places?: PlaceRule[];
|
|
247
|
+
/** ขนาดปุ่ม, px (0.19.10) — 56 when the desk does not say. */
|
|
248
|
+
size?: number;
|
|
236
249
|
}
|
|
237
250
|
let deskLook: DeskLook | null = null;
|
|
238
251
|
/** The face's address for a desk's look: its own path on the support host, the shipped one, or none (the glyph). Pure. */
|
|
@@ -251,6 +264,15 @@ function wearLook(look: DeskLook | null): void {
|
|
|
251
264
|
const color = look?.color && /^#[0-9a-f]{6}$/i.test(look.color) ? look.color : null;
|
|
252
265
|
if (color) root.style.setProperty("--lw-chat-color", color);
|
|
253
266
|
else root.style.removeProperty("--lw-chat-color");
|
|
267
|
+
// Its size (0.19.10): the button drawn so, and every place it stands, the panel and the call's card measured from it.
|
|
268
|
+
const s = bubbleSize(look?.size);
|
|
269
|
+
if (s !== size) {
|
|
270
|
+
size = s;
|
|
271
|
+
if (s === SIZE) root.style.removeProperty("--lw-chat-size");
|
|
272
|
+
else root.style.setProperty("--lw-chat-size", `${s}px`);
|
|
273
|
+
columns = null;
|
|
274
|
+
layout();
|
|
275
|
+
}
|
|
254
276
|
const face = shadow?.querySelector<HTMLImageElement>(".face");
|
|
255
277
|
const url = lookFaceUrl(getConfig().host, look);
|
|
256
278
|
// Its rules and its switch may have changed where it stands.
|
|
@@ -369,7 +391,7 @@ function readColumn(side: Side, x: number): Rect[] {
|
|
|
369
391
|
const k = `${side}:${x}`;
|
|
370
392
|
let boxes = columns.boxes.get(k);
|
|
371
393
|
if (!boxes) {
|
|
372
|
-
const col = side === "right" ? { left: v.w - x -
|
|
394
|
+
const col = side === "right" ? { left: v.w - x - size, right: v.w - x } : { left: x, right: x + size };
|
|
373
395
|
boxes = scanColumns([col], v, { extra: avoidSetting().extra })[0] ?? [];
|
|
374
396
|
columns.boxes.set(k, boxes);
|
|
375
397
|
}
|
|
@@ -452,7 +474,7 @@ const onPageSettled = (e: Event) => {
|
|
|
452
474
|
const r = e.target instanceof Element ? e.target.getBoundingClientRect() : null;
|
|
453
475
|
const v = view();
|
|
454
476
|
const x = spot.x;
|
|
455
|
-
const inColumn = !!r && r.width > 0 && (r.left < x +
|
|
477
|
+
const inColumn = !!r && r.width > 0 && (r.left < x + size || r.right > v.w - x - size);
|
|
456
478
|
queueRescan(inColumn ? "soon" : "later");
|
|
457
479
|
};
|
|
458
480
|
/** What a person did, or the window itself changed: looked at at once. */
|
|
@@ -500,16 +522,16 @@ function layout(): void {
|
|
|
500
522
|
if (!bubble || !panel) return;
|
|
501
523
|
const v = view();
|
|
502
524
|
const want = wanted();
|
|
503
|
-
const wantY = clampBubbleY(want.y, v.h);
|
|
525
|
+
const wantY = clampBubbleY(want.y, v.h, size);
|
|
504
526
|
// While the panel is open it stays where it was opened from — never moved under the person's eyes.
|
|
505
527
|
const wish = `${pagePath()}|${want.side}|${want.x}|${wantY}`;
|
|
506
528
|
const prev = shown && shownFor === wish ? shown : null;
|
|
507
529
|
const home = { side: want.side, x: want.x, y: wantY };
|
|
508
530
|
const placing = !!columns && avoidSetting().on;
|
|
509
|
-
const free = !isOpen || !shown ? (placing ? placeSpot(home, readColumn, v,
|
|
531
|
+
const free = !isOpen || !shown ? (placing ? placeSpot(home, readColumn, v, size, MARGIN, Math.max(MARGIN, v.h - size - MARGIN), prev) : home) : shown;
|
|
510
532
|
shown = { side: free.side, x: free.x, y: free.y };
|
|
511
533
|
shownFor = wish;
|
|
512
|
-
if (placing) placedSig = JSON.stringify([blockedRanges(readColumn(home.side, home.x), home.side === "right" ? { left: v.w - home.x -
|
|
534
|
+
if (placing) placedSig = JSON.stringify([blockedRanges(readColumn(home.side, home.x), home.side === "right" ? { left: v.w - home.x - size, right: v.w - home.x } : { left: home.x, right: home.x + size }, v.h, size), shown]);
|
|
513
535
|
const at = shown;
|
|
514
536
|
const y = at.y;
|
|
515
537
|
const other = at.side === "right" ? "left" : "right";
|
|
@@ -521,11 +543,11 @@ function layout(): void {
|
|
|
521
543
|
const p = clampPanel(panelAt, box, v);
|
|
522
544
|
Object.assign(panel.style, { left: `${p.x}px`, top: `${p.y}px`, right: "", bottom: "", height: `${box.h}px` });
|
|
523
545
|
} else {
|
|
524
|
-
const a = anchorPanel(at, v.h);
|
|
546
|
+
const a = anchorPanel(at, v.h, size);
|
|
525
547
|
Object.assign(panel.style, { [at.side]: `${at.x}px`, [other]: "", bottom: a.bottom !== undefined ? `${a.bottom}px` : "", top: a.top !== undefined ? `${a.top}px` : "", height: `${a.height}px` });
|
|
526
548
|
}
|
|
527
549
|
// The call's card and frame sit above the bubble while it is there and low on their side (ring.ts, callFrame.ts).
|
|
528
|
-
const lift = root && root.style.display !== "none" && bubble.style.display !== "none" ? liftFor(at) : 0;
|
|
550
|
+
const lift = root && root.style.display !== "none" && bubble.style.display !== "none" ? liftFor(at, size) : 0;
|
|
529
551
|
// Written only when it differs from what <html> carries (read back, so a host that rewrites its style attribute
|
|
530
552
|
// gets it again): a property there restyles the host's whole page, and layout() runs on every read of the page.
|
|
531
553
|
const liftNow = lift ? `${lift}px` : "";
|
|
@@ -542,6 +564,14 @@ let pressed: { id: number; sx: number; sy: number; moved: boolean } | null = nul
|
|
|
542
564
|
let swallowClick = false;
|
|
543
565
|
function onBubbleDown(e: PointerEvent): void {
|
|
544
566
|
if (e.button !== 0) return;
|
|
567
|
+
/*
|
|
568
|
+
* The press is the bubble's alone (0.19.10; the owner, 11-02: "it can move only top/bottom on the right side … it
|
|
569
|
+
* cannot [move to] the left"): the bubble follows the pointer at once, and the browser then looks for what to drag at
|
|
570
|
+
* the point first pressed — the host page's own link or picture under it there (a left menu's link) — and starts
|
|
571
|
+
* dragging THAT, cancelling ours (pointercancel): the bubble went back where it was. Taken here, no native drag or
|
|
572
|
+
* text selection begins; the press is still a click, and the panel is still focused when it opens.
|
|
573
|
+
*/
|
|
574
|
+
e.preventDefault();
|
|
545
575
|
pressed = { id: e.pointerId, sx: e.clientX, sy: e.clientY, moved: false };
|
|
546
576
|
try {
|
|
547
577
|
bubble?.setPointerCapture(e.pointerId);
|
|
@@ -554,7 +584,7 @@ function onBubbleMove(e: PointerEvent): void {
|
|
|
554
584
|
if (!pressed.moved && Math.hypot(e.clientX - pressed.sx, e.clientY - pressed.sy) < 6) return;
|
|
555
585
|
pressed.moved = true;
|
|
556
586
|
bubble.classList.add("dragging");
|
|
557
|
-
Object.assign(bubble.style, { left: `${e.clientX -
|
|
587
|
+
Object.assign(bubble.style, { left: `${e.clientX - size / 2}px`, top: `${e.clientY - size / 2}px`, right: "", bottom: "" });
|
|
558
588
|
}
|
|
559
589
|
function onBubbleUp(e: PointerEvent): void {
|
|
560
590
|
if (!pressed || e.pointerId !== pressed.id) return;
|
|
@@ -566,7 +596,7 @@ function onBubbleUp(e: PointerEvent): void {
|
|
|
566
596
|
swallowClick = true;
|
|
567
597
|
setTimeout(() => (swallowClick = false), 0);
|
|
568
598
|
if (e.type === "pointerup") {
|
|
569
|
-
spot = settleBubble(e.clientX, e.clientY, view(), chatPlace(getConfig().chat)?.x ?? 16);
|
|
599
|
+
spot = settleBubble(e.clientX, e.clientY, view(), chatPlace(getConfig().chat)?.x ?? 16, size);
|
|
570
600
|
movedByHand = true;
|
|
571
601
|
// Moved by hand: the panel opens by it again.
|
|
572
602
|
panelAt = null;
|
|
@@ -772,6 +802,7 @@ export function refreshSupportChat(): Promise<void> {
|
|
|
772
802
|
|
|
773
803
|
export function unmountSupportChat(): void {
|
|
774
804
|
deskLook = null;
|
|
805
|
+
size = SIZE;
|
|
775
806
|
stopFrames?.();
|
|
776
807
|
stopFrames = null;
|
|
777
808
|
window.removeEventListener("message", onMessage);
|