@financial-times/custom-code-component 2.0.4 → 2.0.6
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 +34 -1
- package/dist/client-metrics-adaptor.d.ts +107 -0
- package/dist/client-metrics-adaptor.js +98 -0
- package/dist/client-metrics-adaptor.js.map +1 -0
- package/dist/custom-element.d.ts +2 -3
- package/dist/custom-element.js +79 -74
- package/dist/custom-element.js.map +1 -1
- package/package.json +7 -3
- package/src/client-metrics-adaptor.ts +188 -0
- package/src/custom-code-component.ts +30 -23
package/README.md
CHANGED
|
@@ -58,4 +58,37 @@ export default (shadowRoot, props, ...children) => {
|
|
|
58
58
|
* `data-asset-type="custom-code-component"`
|
|
59
59
|
* Part of spec.
|
|
60
60
|
* <any other attributes>
|
|
61
|
-
* All remaining attributes get passed as an object named `props` to render().
|
|
61
|
+
* All remaining attributes get passed as an object named `props` to render().
|
|
62
|
+
|
|
63
|
+
## client-metrics-adaptor
|
|
64
|
+
|
|
65
|
+
This module is an adaptor of the [dotcom-reliability-kit client metrics package](https://github.com/Financial-Times/dotcom-reliability-kit/tree/main/packages/client-metrics-web) to help integrating RUM metrics for the Custom Code Components.
|
|
66
|
+
|
|
67
|
+
### Requirements
|
|
68
|
+
|
|
69
|
+
To use it, you are required to have pre-installed the client-metrics-web package.
|
|
70
|
+
|
|
71
|
+
### Options
|
|
72
|
+
|
|
73
|
+
- **enrichEventCb** (optional): function to enrich the event payload before is sent to AWS RUM
|
|
74
|
+
- **shouldIgnoreEventCb** (optional): function that checks if the event should be sent or not to AWS RUM
|
|
75
|
+
|
|
76
|
+
### Usage:
|
|
77
|
+
|
|
78
|
+
Initialise the ClientMetrics Adaptor in your project to start listening to CCC Events and dispatch automatically AWS RUM events
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
#### example.jsx
|
|
82
|
+
|
|
83
|
+
```js
|
|
84
|
+
import { MetricsClient } from '@dotcom-reliability-kit/client-metrics-web';
|
|
85
|
+
import * as ClientMetricsAdaptor from '@financial-times/custom-code-component';
|
|
86
|
+
|
|
87
|
+
const client = new MetricsClient({
|
|
88
|
+
// Options go here
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
ClientMetricsAdaptor.init(client, {
|
|
92
|
+
enrichEventCb: enrichCCCEventWithHomepageContext,
|
|
93
|
+
shouldIgnoreEventCb: shouldIgnoreCCCEvent,
|
|
94
|
+
});
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
declare class CCCEvent extends Event {
|
|
2
|
+
component: ComponentPath;
|
|
3
|
+
source?: string;
|
|
4
|
+
static eventType: string;
|
|
5
|
+
constructor(eventType: string | undefined, detail: {
|
|
6
|
+
component: ComponentPath;
|
|
7
|
+
source?: string;
|
|
8
|
+
}, opts?: EventInit);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
declare class ComponentPath {
|
|
12
|
+
org: string;
|
|
13
|
+
repo: string;
|
|
14
|
+
name: string;
|
|
15
|
+
versionRange: string;
|
|
16
|
+
constructor(path?: ComponentPathType | string);
|
|
17
|
+
set path(path: ComponentPathType | string);
|
|
18
|
+
get path(): string;
|
|
19
|
+
get isValid(): boolean;
|
|
20
|
+
toString(): string;
|
|
21
|
+
static fromString(p?: string | null, v?: string | null): ComponentPath;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
declare type ComponentPathType = {
|
|
25
|
+
org: string;
|
|
26
|
+
repo: string;
|
|
27
|
+
name: string;
|
|
28
|
+
versionRange: string;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export declare const DEFAULT_VALUE = "uknown";
|
|
32
|
+
|
|
33
|
+
export declare const EVENT_TYPES: Record<string, EventType>;
|
|
34
|
+
|
|
35
|
+
declare type EventType = {
|
|
36
|
+
namespace: string;
|
|
37
|
+
payloadFn: (event: GenericCCCEvent) => Record<string, unknown>;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export declare type GenericCCCEvent = CCCEvent | ErrorEvent;
|
|
41
|
+
|
|
42
|
+
export declare function getComponentProps(eventComponentProp: ComponentPathType): {
|
|
43
|
+
name: string;
|
|
44
|
+
org: string;
|
|
45
|
+
repo: string;
|
|
46
|
+
versionRange: string;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export declare function getEnrichEventProps(event: GenericCCCEvent): Record<string, unknown>;
|
|
50
|
+
|
|
51
|
+
export declare function getErrorPayload(event: GenericCCCEvent): Record<string, unknown>;
|
|
52
|
+
|
|
53
|
+
export declare function getPendingEventsQueue(): PendingEvent[];
|
|
54
|
+
|
|
55
|
+
export declare function getSuccessPayload(event: GenericCCCEvent): Record<string, unknown>;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Initialises the Adaptor with the provided configuration and starts listening to CCC events.
|
|
59
|
+
* If there's any pending event, it'll send them to the Metrics server
|
|
60
|
+
* @param _metricsClient MetricClient instance
|
|
61
|
+
* @param _options Options to configure adaptor
|
|
62
|
+
*/
|
|
63
|
+
export declare function init(_metricsClient: MetricsClient, _options?: Options): void;
|
|
64
|
+
|
|
65
|
+
export declare const MAX_PENDING_EVENTS = 50;
|
|
66
|
+
|
|
67
|
+
export declare type MetricsClient = {
|
|
68
|
+
recordEvent: (namespace: string, payload?: Record<string, unknown>) => void;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export declare function onEventReceived(_event: Event): void;
|
|
72
|
+
|
|
73
|
+
declare type Options = {
|
|
74
|
+
enrichEventCb?: (event: GenericCCCEvent) => Record<string, unknown> | void;
|
|
75
|
+
shouldIgnoreEventCb?: (event: GenericCCCEvent) => boolean;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
declare type PendingEvent = {
|
|
79
|
+
time: number;
|
|
80
|
+
event: GenericCCCEvent;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export declare function processEvent(event: GenericCCCEvent): void;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Sends all pending events waiting to be processed
|
|
87
|
+
*
|
|
88
|
+
* Notes:
|
|
89
|
+
* 1. All these events will be registered in RUM with the same time
|
|
90
|
+
* (at this moment the MetricsClient API doesn't allow to override it)
|
|
91
|
+
* 2. It's safe to process them in bulk since ClientMetrics will send them in bulk
|
|
92
|
+
* (all in 1 request)
|
|
93
|
+
*/
|
|
94
|
+
export declare function sendPendingEvents(): void;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Start listening to CCC events
|
|
98
|
+
* In case there's no MetricsClient registered, it'll store them until they can be sent
|
|
99
|
+
*/
|
|
100
|
+
export declare function startListeners(): void;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Stop listening CCC events
|
|
104
|
+
*/
|
|
105
|
+
export declare function stopListeners(): void;
|
|
106
|
+
|
|
107
|
+
export { }
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
const f = Object.freeze({
|
|
2
|
+
"ccc:ready": {
|
|
3
|
+
namespace: "ccc.success",
|
|
4
|
+
payloadFn: y
|
|
5
|
+
},
|
|
6
|
+
"ccc:error": {
|
|
7
|
+
namespace: "ccc.failure",
|
|
8
|
+
payloadFn: w
|
|
9
|
+
}
|
|
10
|
+
}), i = "uknown", t = [], g = 50;
|
|
11
|
+
let a, n, s = !1;
|
|
12
|
+
function h() {
|
|
13
|
+
s || (window.addEventListener("ccc:error", u), window.addEventListener("ccc:ready", u)), s = !0;
|
|
14
|
+
}
|
|
15
|
+
function b() {
|
|
16
|
+
s && (window.removeEventListener("ccc:error", u), window.removeEventListener("ccc:ready", u)), s = !1, t.length = 0, a = null, n = {};
|
|
17
|
+
}
|
|
18
|
+
function v(e, c) {
|
|
19
|
+
if (!e || typeof e.recordEvent != "function") {
|
|
20
|
+
console.warn("CCC Can't initialise MetricsClientAdaptor");
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
a = e, n = {}, typeof (c == null ? void 0 : c.shouldIgnoreEventCb) == "function" && (n.shouldIgnoreEventCb = c.shouldIgnoreEventCb), typeof (c == null ? void 0 : c.enrichEventCb) == "function" && (n.enrichEventCb = c.enrichEventCb), o(), h();
|
|
24
|
+
}
|
|
25
|
+
function d(e) {
|
|
26
|
+
var c;
|
|
27
|
+
try {
|
|
28
|
+
const r = ((c = n == null ? void 0 : n.enrichEventCb) == null ? void 0 : c.call(n, e)) || {};
|
|
29
|
+
if (typeof r != "object" || Array.isArray(r))
|
|
30
|
+
throw new TypeError("Enrich event callback returned invalid value");
|
|
31
|
+
return r;
|
|
32
|
+
} catch (r) {
|
|
33
|
+
return console.error("CCC RUM event couldn't be enriched", r), {};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function l(e) {
|
|
37
|
+
return {
|
|
38
|
+
name: (e == null ? void 0 : e.name) || i,
|
|
39
|
+
org: (e == null ? void 0 : e.org) || i,
|
|
40
|
+
repo: (e == null ? void 0 : e.repo) || i,
|
|
41
|
+
versionRange: (e == null ? void 0 : e.versionRange) || i
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function y(e) {
|
|
45
|
+
return {
|
|
46
|
+
...d(e),
|
|
47
|
+
component: l(e.component)
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function w(e) {
|
|
51
|
+
const c = e.error, r = c == null ? void 0 : c.name;
|
|
52
|
+
return {
|
|
53
|
+
...d(e),
|
|
54
|
+
component: l(c == null ? void 0 : c.component),
|
|
55
|
+
error: r || i
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function E(e) {
|
|
59
|
+
if (n.shouldIgnoreEventCb && n.shouldIgnoreEventCb(e))
|
|
60
|
+
return;
|
|
61
|
+
if (!a) {
|
|
62
|
+
console.warn("CCC Couldn't process event: ClientMetrics not initialised");
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const c = f[e.type];
|
|
66
|
+
if (!c) {
|
|
67
|
+
console.warn("CCC event.type not registered");
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
a.recordEvent(c.namespace, c.payloadFn(e));
|
|
71
|
+
}
|
|
72
|
+
function u(e) {
|
|
73
|
+
const c = e;
|
|
74
|
+
a ? E(c) : (t.push({ event: c, time: Date.now() }), t.splice(0, t.length - g));
|
|
75
|
+
}
|
|
76
|
+
function o() {
|
|
77
|
+
t.forEach(({ event: e }) => E(e)), t.length = 0;
|
|
78
|
+
}
|
|
79
|
+
function L() {
|
|
80
|
+
return t;
|
|
81
|
+
}
|
|
82
|
+
export {
|
|
83
|
+
i as DEFAULT_VALUE,
|
|
84
|
+
f as EVENT_TYPES,
|
|
85
|
+
g as MAX_PENDING_EVENTS,
|
|
86
|
+
l as getComponentProps,
|
|
87
|
+
d as getEnrichEventProps,
|
|
88
|
+
w as getErrorPayload,
|
|
89
|
+
L as getPendingEventsQueue,
|
|
90
|
+
y as getSuccessPayload,
|
|
91
|
+
v as init,
|
|
92
|
+
u as onEventReceived,
|
|
93
|
+
E as processEvent,
|
|
94
|
+
o as sendPendingEvents,
|
|
95
|
+
h as startListeners,
|
|
96
|
+
b as stopListeners
|
|
97
|
+
};
|
|
98
|
+
//# sourceMappingURL=client-metrics-adaptor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-metrics-adaptor.js","sources":["../src/client-metrics-adaptor.ts"],"sourcesContent":["// MetricsClient type from https://github.com/Financial-Times/dotcom-reliability-kit/tree/main/packages/client-metrics-web\n// We intentionally copied this type here to avoid having version conflicts between this module and it's client\nimport type { ComponentPathType } from './path'\nimport type { CCCEvent } from './events'\n\nexport type MetricsClient = {\n recordEvent: (namespace: string, payload?: Record<string, unknown>) => void\n};\n\nexport type GenericCCCEvent = CCCEvent | ErrorEvent;\n\ntype Options = {\n enrichEventCb?: (event: GenericCCCEvent) => Record<string, unknown> | void\n shouldIgnoreEventCb?: (event: GenericCCCEvent) => boolean\n};\n\ntype PendingEvent = {\n time: number\n event: GenericCCCEvent\n};\n\ntype EventType = {\n namespace: string\n payloadFn: (event: GenericCCCEvent) => Record<string, unknown>\n};\n\nexport const EVENT_TYPES: Record<string, EventType> = Object.freeze({\n 'ccc:ready': {\n namespace: 'ccc.success',\n payloadFn: getSuccessPayload,\n },\n 'ccc:error': {\n namespace: 'ccc.failure',\n payloadFn: getErrorPayload,\n },\n});\n\nexport const DEFAULT_VALUE = 'uknown';\n\nconst pendingEvents: PendingEvent[] = [];\nexport const MAX_PENDING_EVENTS = 50;\nlet metricsClient: MetricsClient | null;\nlet options: Options;\nlet isRunning = false;\n\n/**\n * Start listening to CCC events\n * In case there's no MetricsClient registered, it'll store them until they can be sent\n */\nexport function startListeners() {\n if (!isRunning) {\n window.addEventListener('ccc:error', onEventReceived);\n window.addEventListener('ccc:ready', onEventReceived);\n }\n isRunning = true;\n}\n\n/**\n * Stop listening CCC events\n */\nexport function stopListeners() {\n if (isRunning) {\n window.removeEventListener('ccc:error', onEventReceived);\n window.removeEventListener('ccc:ready', onEventReceived);\n }\n\n isRunning = false;\n pendingEvents.length = 0;\n metricsClient = null;\n options = {};\n}\n\n/**\n * Initialises the Adaptor with the provided configuration and starts listening to CCC events.\n * If there's any pending event, it'll send them to the Metrics server\n * @param _metricsClient MetricClient instance\n * @param _options Options to configure adaptor\n */\nexport function init(_metricsClient: MetricsClient, _options?: Options) {\n if (!_metricsClient || typeof _metricsClient.recordEvent !== 'function') {\n console.warn(\"CCC Can't initialise MetricsClientAdaptor\");\n return;\n }\n\n metricsClient = _metricsClient;\n\n options = {};\n if (typeof _options?.shouldIgnoreEventCb === 'function') {\n options.shouldIgnoreEventCb = _options.shouldIgnoreEventCb;\n }\n if (typeof _options?.enrichEventCb === 'function') {\n options.enrichEventCb = _options.enrichEventCb;\n }\n\n sendPendingEvents();\n startListeners();\n}\n\nexport function getEnrichEventProps(event: GenericCCCEvent) {\n try {\n const props = options?.enrichEventCb?.(event) || {};\n if (typeof props !== 'object' || Array.isArray(props)) {\n throw new TypeError('Enrich event callback returned invalid value');\n }\n return props;\n } catch (error) {\n console.error(\"CCC RUM event couldn't be enriched\", error);\n return {};\n }\n}\n\nexport function getComponentProps(eventComponentProp: ComponentPathType) {\n return {\n name: eventComponentProp?.name || DEFAULT_VALUE,\n org: eventComponentProp?.org || DEFAULT_VALUE,\n repo: eventComponentProp?.repo || DEFAULT_VALUE,\n versionRange: eventComponentProp?.versionRange || DEFAULT_VALUE,\n };\n}\n\nexport function getSuccessPayload(event: GenericCCCEvent): Record<string, unknown> {\n return {\n ...getEnrichEventProps(event),\n component: getComponentProps((event as CCCEvent).component),\n };\n}\n\nexport function getErrorPayload(event: GenericCCCEvent): Record<string, unknown> {\n const error = (event as ErrorEvent).error;\n const errorName = error?.name;\n\n return {\n ...getEnrichEventProps(event),\n component: getComponentProps(error?.component),\n error: errorName || DEFAULT_VALUE,\n };\n}\n\nexport function processEvent(event: GenericCCCEvent) {\n // Stop processing the event if we should ignore it\n if (options.shouldIgnoreEventCb && options.shouldIgnoreEventCb(event)) {\n return;\n }\n\n if (!metricsClient) {\n console.warn(\"CCC Couldn't process event: ClientMetrics not initialised\");\n return;\n }\n\n const eventType = EVENT_TYPES[event.type];\n if (!eventType) {\n console.warn('CCC event.type not registered');\n return;\n }\n\n metricsClient.recordEvent(eventType.namespace, eventType.payloadFn(event));\n}\n\nexport function onEventReceived(_event: Event) {\n // The Event object dispatched from the CCC has extra custom props\n const event = _event as GenericCCCEvent\n\n if (metricsClient) {\n processEvent(event);\n } else {\n pendingEvents.push({ event: event, time: Date.now() });\n // keep only the last MAX_PENDING_EVENTS events (FIFO)\n pendingEvents.splice(0, pendingEvents.length - MAX_PENDING_EVENTS);\n }\n}\n\n/**\n * Sends all pending events waiting to be processed\n *\n * Notes:\n * 1. All these events will be registered in RUM with the same time\n * (at this moment the MetricsClient API doesn't allow to override it)\n * 2. It's safe to process them in bulk since ClientMetrics will send them in bulk\n * (all in 1 request)\n */\nexport function sendPendingEvents() {\n pendingEvents.forEach(({ event }) => processEvent(event));\n pendingEvents.length = 0;\n}\n\nexport function getPendingEventsQueue() {\n return pendingEvents;\n}\n"],"names":["EVENT_TYPES","getSuccessPayload","getErrorPayload","DEFAULT_VALUE","pendingEvents","MAX_PENDING_EVENTS","metricsClient","options","isRunning","startListeners","onEventReceived","stopListeners","init","_metricsClient","_options","sendPendingEvents","getEnrichEventProps","event","_a","props","error","getComponentProps","eventComponentProp","errorName","processEvent","eventType","_event","getPendingEventsQueue"],"mappings":"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"}
|
package/dist/custom-element.d.ts
CHANGED
|
@@ -53,13 +53,12 @@ declare class FTCustomCodeComponent extends HTMLElement {
|
|
|
53
53
|
disconnectedCallback(): void;
|
|
54
54
|
channel: MessageChannel;
|
|
55
55
|
onmessage(): void;
|
|
56
|
-
onunmount(
|
|
56
|
+
onunmount(e: Error): void;
|
|
57
57
|
onready(app: Promise<void>): Promise<void>;
|
|
58
58
|
postMessage(event: any): void;
|
|
59
59
|
mount(prerendered?: ShadowRoot | null): Promise<void>;
|
|
60
60
|
unmount(e: Error): void;
|
|
61
|
-
load(): Promise<(shadowRoot: ShadowRoot, props: any, ssr?: boolean) => {
|
|
62
|
-
unmount: (root: any) => void;
|
|
61
|
+
load(): Promise<(shadowRoot: ShadowRoot, props: any, ssr?: boolean, onErrorCallback?: Function) => {
|
|
63
62
|
onmessage: {
|
|
64
63
|
(...data: any[]): void;
|
|
65
64
|
(message?: any, ...optionalParams: any[]): void;
|
package/dist/custom-element.js
CHANGED
|
@@ -28,7 +28,7 @@ l.prototype.on = function(o, t, e, n) {
|
|
|
28
28
|
throw new TypeError("Invalid event type: " + o);
|
|
29
29
|
if (typeof t == "function" && (n = e, e = t, t = null), n === void 0 && (n = this.captureForType(o)), typeof e != "function")
|
|
30
30
|
throw new TypeError("Handler must be a type of Function");
|
|
31
|
-
return r = this.rootElement, s = this.listenerMap[n ? 1 : 0], s[o] || (r && r.addEventListener(o, this.handle, n), s[o] = []), t ? /^[a-z]+$/i.test(t) ? (c = t, i =
|
|
31
|
+
return r = this.rootElement, s = this.listenerMap[n ? 1 : 0], s[o] || (r && r.addEventListener(o, this.handle, n), s[o] = []), t ? /^[a-z]+$/i.test(t) ? (c = t, i = P) : /^#[a-z0-9\-_]+$/i.test(t) ? (c = t.slice(1), i = I) : (c = t, i = Element.prototype.matches) : (c = null, i = U.bind(this)), s[o].push({
|
|
32
32
|
selector: t,
|
|
33
33
|
handler: e,
|
|
34
34
|
matcher: i,
|
|
@@ -54,8 +54,8 @@ l.prototype.handle = function(o) {
|
|
|
54
54
|
let t, e;
|
|
55
55
|
const n = o.type;
|
|
56
56
|
let r, s, i, c, a = [], h;
|
|
57
|
-
const
|
|
58
|
-
if (o[
|
|
57
|
+
const p = "ftLabsDelegateIgnore";
|
|
58
|
+
if (o[p] === !0)
|
|
59
59
|
return;
|
|
60
60
|
switch (h = o.target, h.nodeType === 3 && (h = h.parentNode), h.correspondingUseElement && (h = h.correspondingUseElement), r = this.rootElement, s = o.eventPhase || (o.target !== o.currentTarget ? 3 : 2), s) {
|
|
61
61
|
case 1:
|
|
@@ -68,17 +68,17 @@ l.prototype.handle = function(o) {
|
|
|
68
68
|
a = this.listenerMap[0][n];
|
|
69
69
|
break;
|
|
70
70
|
}
|
|
71
|
-
let
|
|
71
|
+
let u = [];
|
|
72
72
|
for (e = a.length; h && e; ) {
|
|
73
73
|
for (t = 0; t < e && (i = a[t], !!i); t++)
|
|
74
|
-
h.tagName && ["button", "input", "select", "textarea"].indexOf(h.tagName.toLowerCase()) > -1 && h.hasAttribute("disabled") ?
|
|
74
|
+
h.tagName && ["button", "input", "select", "textarea"].indexOf(h.tagName.toLowerCase()) > -1 && h.hasAttribute("disabled") ? u = [] : i.matcher.call(h, i.matcherParam, h) && u.push([o, h, i]);
|
|
75
75
|
if (h === r || (e = a.length, h = h.parentElement || h.parentNode, h instanceof HTMLDocument))
|
|
76
76
|
break;
|
|
77
77
|
}
|
|
78
78
|
let L;
|
|
79
|
-
for (t = 0; t <
|
|
80
|
-
if (!(this._removedListeners.indexOf(
|
|
81
|
-
|
|
79
|
+
for (t = 0; t < u.length; t++)
|
|
80
|
+
if (!(this._removedListeners.indexOf(u[t][2]) > -1) && (c = this.fire.apply(this, u[t]), c === !1)) {
|
|
81
|
+
u[t][0][p] = !0, u[t][0].preventDefault(), L = !1;
|
|
82
82
|
break;
|
|
83
83
|
}
|
|
84
84
|
return L;
|
|
@@ -86,10 +86,10 @@ l.prototype.handle = function(o) {
|
|
|
86
86
|
l.prototype.fire = function(o, t, e) {
|
|
87
87
|
return e.handler.call(t, o, t);
|
|
88
88
|
};
|
|
89
|
-
function
|
|
89
|
+
function P(o, t) {
|
|
90
90
|
return o.toLowerCase() === t.tagName.toLowerCase();
|
|
91
91
|
}
|
|
92
|
-
function
|
|
92
|
+
function U(o, t) {
|
|
93
93
|
return this.rootElement === window ? (
|
|
94
94
|
// Match the outer document (dispatched from document)
|
|
95
95
|
t === document || // The <html> element (dispatched from document.body or document.documentElement)
|
|
@@ -97,20 +97,20 @@ function P(o, t) {
|
|
|
97
97
|
t === window
|
|
98
98
|
) : this.rootElement === t;
|
|
99
99
|
}
|
|
100
|
-
function
|
|
100
|
+
function I(o, t) {
|
|
101
101
|
return o === t.id;
|
|
102
102
|
}
|
|
103
103
|
l.prototype.destroy = function() {
|
|
104
104
|
this.off(), this.root();
|
|
105
105
|
};
|
|
106
|
-
function
|
|
106
|
+
function C(o) {
|
|
107
107
|
return typeof o == "string" ? o.trim() : o;
|
|
108
108
|
}
|
|
109
|
-
function
|
|
109
|
+
function N(o, t) {
|
|
110
110
|
for (const e in o)
|
|
111
111
|
t[e] ? console.warn(`You can't set a custom property called ${e}`) : t[e] = o[e];
|
|
112
112
|
}
|
|
113
|
-
const
|
|
113
|
+
const m = Object.freeze({
|
|
114
114
|
DEBUG: 0,
|
|
115
115
|
INFO: 1,
|
|
116
116
|
WARN: 2,
|
|
@@ -118,51 +118,51 @@ const u = Object.freeze({
|
|
|
118
118
|
TEST: 4,
|
|
119
119
|
DEFAULT: 2
|
|
120
120
|
});
|
|
121
|
-
function
|
|
121
|
+
function D(o) {
|
|
122
122
|
const t = o == null ? void 0 : o.toLowerCase();
|
|
123
|
-
return t === "debug" ?
|
|
123
|
+
return t === "debug" ? m.DEBUG : t === "info" ? m.INFO : t === "warn" ? m.WARN : t === "error" ? m.ERROR : t === "test" ? m.TEST : m.DEFAULT;
|
|
124
124
|
}
|
|
125
|
-
class
|
|
126
|
-
constructor({ level: t =
|
|
127
|
-
level:
|
|
125
|
+
class O {
|
|
126
|
+
constructor({ level: t = m.DEFAULT } = {
|
|
127
|
+
level: m.DEFAULT
|
|
128
128
|
}) {
|
|
129
129
|
this.log = this.debug, this.level = t;
|
|
130
130
|
}
|
|
131
131
|
debug(...t) {
|
|
132
|
-
this.level <=
|
|
132
|
+
this.level <= m.DEBUG && console.info(...t);
|
|
133
133
|
}
|
|
134
134
|
info(...t) {
|
|
135
|
-
this.level <=
|
|
135
|
+
this.level <= m.INFO && console.info(...t);
|
|
136
136
|
}
|
|
137
137
|
warn(...t) {
|
|
138
|
-
this.level <=
|
|
138
|
+
this.level <= m.WARN && console.warn(...t);
|
|
139
139
|
}
|
|
140
140
|
error(...t) {
|
|
141
|
-
this.level <=
|
|
141
|
+
this.level <= m.ERROR && console.error(...t);
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
|
-
const
|
|
144
|
+
const M = (o, t, e) => {
|
|
145
145
|
const n = Array.from((o == null ? void 0 : o.querySelectorAll(e)) ?? []), r = n.findIndex((s) => s === t);
|
|
146
146
|
if (r !== -1)
|
|
147
147
|
return {
|
|
148
148
|
siblings: n.length,
|
|
149
149
|
position: r
|
|
150
150
|
};
|
|
151
|
-
},
|
|
151
|
+
}, x = [
|
|
152
152
|
"nodeName",
|
|
153
153
|
"className",
|
|
154
154
|
"id",
|
|
155
155
|
"href",
|
|
156
156
|
"text",
|
|
157
157
|
"role"
|
|
158
|
-
],
|
|
158
|
+
], j = (o) => {
|
|
159
159
|
const t = {};
|
|
160
|
-
for (const e of
|
|
160
|
+
for (const e of x) {
|
|
161
161
|
const n = o[e] || o.getAttribute(e) || o.hasAttribute(e);
|
|
162
|
-
n !== void 0 && (typeof n == "boolean" ? t[e] = n : t[e] =
|
|
162
|
+
n !== void 0 && (typeof n == "boolean" ? t[e] = n : t[e] = C(n));
|
|
163
163
|
}
|
|
164
164
|
return t;
|
|
165
|
-
},
|
|
165
|
+
}, F = (o) => {
|
|
166
166
|
try {
|
|
167
167
|
const t = JSON.parse(o), e = Object.prototype.toString.call(t);
|
|
168
168
|
return [e === "[object Object]" || e === "[object Array]", t];
|
|
@@ -170,31 +170,31 @@ const D = (o, t, e) => {
|
|
|
170
170
|
return [!1, null];
|
|
171
171
|
}
|
|
172
172
|
}, _ = (o) => {
|
|
173
|
-
const [t, e] =
|
|
173
|
+
const [t, e] = F(o);
|
|
174
174
|
return t ? e : o;
|
|
175
|
-
},
|
|
175
|
+
}, H = (o, t) => (o.filter(
|
|
176
176
|
(e) => e.name.match(/^data-trackable|^data-o-|^aria-/i)
|
|
177
177
|
).forEach((e) => {
|
|
178
178
|
t[e.name] = e.value;
|
|
179
|
-
}), t),
|
|
179
|
+
}), t), z = (o, t, e) => {
|
|
180
180
|
const n = {};
|
|
181
|
-
return e &&
|
|
181
|
+
return e && x.forEach((r) => {
|
|
182
182
|
typeof t[r] < "u" && r !== "id" && (n[r] = t[r]);
|
|
183
183
|
}), o.filter((r) => r.name.match(/^data-trackable-context-/i)).forEach((r) => {
|
|
184
184
|
n[r.name.replace("data-trackable-context-", "")] = _(r.value);
|
|
185
185
|
}), n;
|
|
186
186
|
};
|
|
187
|
-
function
|
|
187
|
+
function q(o, t) {
|
|
188
188
|
const e = o, n = e != null && e.getAttribute("data-trackable") ? `[data-trackable="${e.getAttribute("data-trackable")}"]` : e == null ? void 0 : e.nodeName, r = [], s = {};
|
|
189
189
|
for (; o && o !== t; ) {
|
|
190
|
-
const i =
|
|
191
|
-
let a =
|
|
190
|
+
const i = j(o), c = Array.from(o.attributes);
|
|
191
|
+
let a = H(c, i);
|
|
192
192
|
a["data-trackable"] && (a = Object.assign(
|
|
193
193
|
a,
|
|
194
|
-
|
|
194
|
+
M(o, e, n)
|
|
195
195
|
)), r.push(a);
|
|
196
|
-
const h =
|
|
197
|
-
|
|
196
|
+
const h = z(c, i, o === e);
|
|
197
|
+
N(h, s), o = o.parentNode;
|
|
198
198
|
}
|
|
199
199
|
return { trace: r, customContext: s };
|
|
200
200
|
}
|
|
@@ -210,7 +210,7 @@ class Y {
|
|
|
210
210
|
elements: c = 'a, button, input, [role="button"]',
|
|
211
211
|
logger: a
|
|
212
212
|
}) {
|
|
213
|
-
this.cccId = t, this.cccName = e, this.subtype = n, this.teamName = r, this.shadowRoot = s, this.category = i, this.elements = c, this.isInitialised = !1, this.log = a ?? new
|
|
213
|
+
this.cccId = t, this.cccName = e, this.subtype = n, this.teamName = r, this.shadowRoot = s, this.category = i, this.elements = c, this.isInitialised = !1, this.log = a ?? new O();
|
|
214
214
|
}
|
|
215
215
|
// Get properties for the event (as opposed to properties of the clicked element)
|
|
216
216
|
getEventProperties(t) {
|
|
@@ -218,7 +218,7 @@ class Y {
|
|
|
218
218
|
for (const n of V)
|
|
219
219
|
if (t[n])
|
|
220
220
|
try {
|
|
221
|
-
e[n] =
|
|
221
|
+
e[n] = C(t[n]);
|
|
222
222
|
} catch (r) {
|
|
223
223
|
this.log.info(r);
|
|
224
224
|
}
|
|
@@ -227,13 +227,13 @@ class Y {
|
|
|
227
227
|
// Controller for handling click events
|
|
228
228
|
handleClickEvent(t, e) {
|
|
229
229
|
return (n, r) => {
|
|
230
|
-
const s = this.getEventProperties(n), { trace: i, customContext: c } =
|
|
230
|
+
const s = this.getEventProperties(n), { trace: i, customContext: c } = q(r, e);
|
|
231
231
|
s.custom = r.dataset && r.dataset.custom ? JSON.parse(r.dataset.custom) : null, s.domPathTokens = i, s.component = {
|
|
232
232
|
id: this.cccId,
|
|
233
233
|
name: this.cccName,
|
|
234
234
|
type: "custom-code-component",
|
|
235
235
|
subtype: this.subtype
|
|
236
|
-
}, s.teamName = this.teamName, s.url = document.URL,
|
|
236
|
+
}, s.teamName = this.teamName, s.url = document.URL, N(c, s), s.method = "ftCustomAnalytics", t = { ...t, ...s }, document.body.dispatchEvent(
|
|
237
237
|
new CustomEvent("oTracking.event", {
|
|
238
238
|
detail: t,
|
|
239
239
|
bubbles: !0,
|
|
@@ -330,7 +330,7 @@ class w extends d {
|
|
|
330
330
|
super(t, { ...e, cause: "Import error" }), this.name = "CCCImportError";
|
|
331
331
|
}
|
|
332
332
|
}
|
|
333
|
-
class
|
|
333
|
+
class $ extends d {
|
|
334
334
|
constructor(t, e) {
|
|
335
335
|
super(t, { ...e, cause: "Render error" }), this.name = "CCCRenderError";
|
|
336
336
|
}
|
|
@@ -352,20 +352,20 @@ const b = class b extends Event {
|
|
|
352
352
|
};
|
|
353
353
|
b.eventType = "ccc:event";
|
|
354
354
|
let g = b;
|
|
355
|
-
const
|
|
355
|
+
const E = class E extends g {
|
|
356
356
|
constructor(t, e) {
|
|
357
|
-
super(
|
|
357
|
+
super(E.eventType, t, e);
|
|
358
358
|
}
|
|
359
359
|
};
|
|
360
|
-
|
|
361
|
-
let T =
|
|
362
|
-
const
|
|
360
|
+
E.eventType = "ccc:connected";
|
|
361
|
+
let T = E;
|
|
362
|
+
const y = class y extends g {
|
|
363
363
|
constructor(t, e) {
|
|
364
|
-
super(
|
|
364
|
+
super(y.eventType, t, e);
|
|
365
365
|
}
|
|
366
366
|
};
|
|
367
|
-
|
|
368
|
-
let k =
|
|
367
|
+
y.eventType = "ccc:ready";
|
|
368
|
+
let k = y;
|
|
369
369
|
const v = class v extends g {
|
|
370
370
|
constructor(t, e) {
|
|
371
371
|
super(v.eventType, t, e), this.intersecting = !1, this.intersecting = t.intersecting, this.entry = t.entry;
|
|
@@ -471,8 +471,8 @@ class tt extends HTMLElement {
|
|
|
471
471
|
`.trim(), document.head.appendChild(e);
|
|
472
472
|
const n = document.createElement("script");
|
|
473
473
|
n.type = "module", n.src = `${(s = this.testUrl) == null ? void 0 : s.origin}/@vite/client`, document.head.appendChild(n);
|
|
474
|
-
}, this.log = new
|
|
475
|
-
level:
|
|
474
|
+
}, this.log = new O({
|
|
475
|
+
level: D(this.getAttribute("log"))
|
|
476
476
|
});
|
|
477
477
|
const t = HTMLElement.prototype.hasOwnProperty("attachInternals");
|
|
478
478
|
try {
|
|
@@ -492,7 +492,7 @@ class tt extends HTMLElement {
|
|
|
492
492
|
}
|
|
493
493
|
}
|
|
494
494
|
emitError(t) {
|
|
495
|
-
if (t instanceof d)
|
|
495
|
+
if (console.debug("ccc#emitError", t), t instanceof d)
|
|
496
496
|
this.dispatchEvent(
|
|
497
497
|
new ErrorEvent("ccc:error", {
|
|
498
498
|
bubbles: !0,
|
|
@@ -520,11 +520,20 @@ class tt extends HTMLElement {
|
|
|
520
520
|
}
|
|
521
521
|
disconnectedCallback() {
|
|
522
522
|
const t = this.getAttribute("path");
|
|
523
|
-
this.log.info(`<custom-code-component:${t}> disconnected`),
|
|
523
|
+
this.log.info(`<custom-code-component:${t}> disconnected`), this.observer.disconnect();
|
|
524
524
|
}
|
|
525
525
|
onmessage() {
|
|
526
526
|
}
|
|
527
527
|
onunmount(t) {
|
|
528
|
+
if (t instanceof Error) {
|
|
529
|
+
const e = new $(t.message, {
|
|
530
|
+
error: t,
|
|
531
|
+
component: this.component
|
|
532
|
+
});
|
|
533
|
+
requestAnimationFrame(() => {
|
|
534
|
+
this.emitError(e), this.unmount(e);
|
|
535
|
+
});
|
|
536
|
+
}
|
|
528
537
|
}
|
|
529
538
|
async onready(t) {
|
|
530
539
|
try {
|
|
@@ -536,7 +545,7 @@ class tt extends HTMLElement {
|
|
|
536
545
|
), this.dataset.cccReady = "true", delete this.dataset.cccError, this.observer.observe(this);
|
|
537
546
|
} catch (e) {
|
|
538
547
|
if (e instanceof Error) {
|
|
539
|
-
const n = new
|
|
548
|
+
const n = new $(e.message, {
|
|
540
549
|
error: e,
|
|
541
550
|
component: this.component
|
|
542
551
|
});
|
|
@@ -585,11 +594,7 @@ class tt extends HTMLElement {
|
|
|
585
594
|
"text-decoration: underline;",
|
|
586
595
|
" attribute instead."
|
|
587
596
|
));
|
|
588
|
-
const {
|
|
589
|
-
unmount: a,
|
|
590
|
-
onmessage: h,
|
|
591
|
-
ready: m = Promise.resolve()
|
|
592
|
-
} = this.app(
|
|
597
|
+
const { onmessage: a, ready: h = Promise.resolve() } = this.app(
|
|
593
598
|
s,
|
|
594
599
|
{
|
|
595
600
|
...i ?? c,
|
|
@@ -599,9 +604,10 @@ class tt extends HTMLElement {
|
|
|
599
604
|
prerendered: !!t,
|
|
600
605
|
children: this.children
|
|
601
606
|
},
|
|
602
|
-
r
|
|
607
|
+
r,
|
|
608
|
+
this.onunmount.bind(this)
|
|
603
609
|
) || {};
|
|
604
|
-
a && (this.
|
|
610
|
+
a && (this.onmessage = a), this.onready(h);
|
|
605
611
|
}
|
|
606
612
|
} catch (r) {
|
|
607
613
|
throw this.log.info(
|
|
@@ -614,7 +620,6 @@ class tt extends HTMLElement {
|
|
|
614
620
|
// slot on failure
|
|
615
621
|
unmount(t) {
|
|
616
622
|
var n;
|
|
617
|
-
this.onunmount(t);
|
|
618
623
|
const e = this.querySelector(
|
|
619
624
|
"template[data-component-fallback]"
|
|
620
625
|
) ?? this.querySelector("template");
|
|
@@ -634,7 +639,7 @@ class tt extends HTMLElement {
|
|
|
634
639
|
try {
|
|
635
640
|
return await new Promise(
|
|
636
641
|
(a, h) => {
|
|
637
|
-
const
|
|
642
|
+
const p = setTimeout(() => {
|
|
638
643
|
this.log.error("CCC import timeout error"), h(
|
|
639
644
|
new J({
|
|
640
645
|
component: this.component,
|
|
@@ -647,9 +652,9 @@ class tt extends HTMLElement {
|
|
|
647
652
|
/* webpackIgnore: true */
|
|
648
653
|
this.source
|
|
649
654
|
/* @vite-ignore */
|
|
650
|
-
).then(({ default:
|
|
651
|
-
if (
|
|
652
|
-
clearTimeout(
|
|
655
|
+
).then(({ default: u }) => {
|
|
656
|
+
if (u)
|
|
657
|
+
clearTimeout(p), a(u);
|
|
653
658
|
else
|
|
654
659
|
throw new w(
|
|
655
660
|
"No component renderer default export found",
|
|
@@ -658,16 +663,16 @@ class tt extends HTMLElement {
|
|
|
658
663
|
source: this.source
|
|
659
664
|
}
|
|
660
665
|
);
|
|
661
|
-
}).catch((
|
|
662
|
-
clearTimeout(
|
|
663
|
-
new w(
|
|
666
|
+
}).catch((u) => {
|
|
667
|
+
clearTimeout(p), this.log.error(u), u instanceof Error && !(u instanceof w) ? h(
|
|
668
|
+
new w(u.message, {
|
|
664
669
|
component: this.component,
|
|
665
670
|
source: this.source
|
|
666
671
|
})
|
|
667
|
-
) : h(
|
|
672
|
+
) : h(u);
|
|
668
673
|
});
|
|
669
674
|
else
|
|
670
|
-
throw clearTimeout(
|
|
675
|
+
throw clearTimeout(p), new w(`Unable to mount ${t}`, {
|
|
671
676
|
component: this.component,
|
|
672
677
|
source: this.source
|
|
673
678
|
});
|