@financial-times/custom-code-component 1.9.3 → 1.9.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/custom-code-component.js +358 -345
- package/dist/tracking.d.ts +24 -0
- package/package.json +1 -1
- package/src/custom-code-component.ts +12 -9
- package/src/tracking.ts +145 -0
- package/dist/analytics.d.ts +0 -11
- package/src/analytics.ts +0 -137
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
declare class Tracking {
|
|
2
|
+
cccId: string;
|
|
3
|
+
cccName: string;
|
|
4
|
+
subtype: string;
|
|
5
|
+
teamName: string;
|
|
6
|
+
shadowRoot: ShadowRoot | null;
|
|
7
|
+
category: string;
|
|
8
|
+
elements: string | string[];
|
|
9
|
+
isInitialised: boolean;
|
|
10
|
+
constructor({ id, name, subtype, teamName, shadowRoot, category, elements, }?: {
|
|
11
|
+
id?: string;
|
|
12
|
+
name?: string;
|
|
13
|
+
subtype?: string;
|
|
14
|
+
teamName?: string;
|
|
15
|
+
shadowRoot?: any;
|
|
16
|
+
category?: string;
|
|
17
|
+
elements?: string;
|
|
18
|
+
});
|
|
19
|
+
getEventProperties(event: any): {};
|
|
20
|
+
handleClickEvent(eventData: any, root: any): (clickEvent: any, clickElement: any) => void;
|
|
21
|
+
sendSpoorEvent(triggerAction: any, extraDetail: any): void;
|
|
22
|
+
init(id: any): void;
|
|
23
|
+
}
|
|
24
|
+
export default Tracking;
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import { ContentTree } from "@financial-times/content-tree";
|
|
7
7
|
import { BaseRenderer } from "../../ccc-sdk/src/renderers/AbstractBaseRenderer";
|
|
8
|
-
import
|
|
8
|
+
import Tracking from "./tracking";
|
|
9
9
|
|
|
10
10
|
class FTCustomCodeComponent extends HTMLElement {
|
|
11
11
|
app: typeof BaseRenderer.prototype.render;
|
|
@@ -24,6 +24,7 @@ class FTCustomCodeComponent extends HTMLElement {
|
|
|
24
24
|
]);
|
|
25
25
|
|
|
26
26
|
source: string;
|
|
27
|
+
tracking: Tracking;
|
|
27
28
|
|
|
28
29
|
async mount() {
|
|
29
30
|
if (!this.app) {
|
|
@@ -45,6 +46,14 @@ class FTCustomCodeComponent extends HTMLElement {
|
|
|
45
46
|
// Clear old children
|
|
46
47
|
this.shadowRoot?.replaceChildren();
|
|
47
48
|
|
|
49
|
+
// Create tracking instance
|
|
50
|
+
this.tracking = new Tracking({
|
|
51
|
+
name: `${this.getAttribute("path")}@${this.getAttribute("version")}`,
|
|
52
|
+
subtype: "interactive",
|
|
53
|
+
teamName: "djd",
|
|
54
|
+
shadowRoot: this.shadowRoot as ShadowRoot,
|
|
55
|
+
});
|
|
56
|
+
|
|
48
57
|
const { unmount, onmessage } =
|
|
49
58
|
App(
|
|
50
59
|
shadow,
|
|
@@ -52,7 +61,7 @@ class FTCustomCodeComponent extends HTMLElement {
|
|
|
52
61
|
...extraProps,
|
|
53
62
|
data,
|
|
54
63
|
port: this.channel.port2,
|
|
55
|
-
tracking,
|
|
64
|
+
tracking: this.tracking,
|
|
56
65
|
},
|
|
57
66
|
...this.children
|
|
58
67
|
) || {};
|
|
@@ -162,13 +171,7 @@ class FTCustomCodeComponent extends HTMLElement {
|
|
|
162
171
|
}
|
|
163
172
|
|
|
164
173
|
try {
|
|
165
|
-
tracking.init(
|
|
166
|
-
{
|
|
167
|
-
id: this.getAttribute("path") as string,
|
|
168
|
-
subtype: "interactive",
|
|
169
|
-
},
|
|
170
|
-
this.shadowRoot
|
|
171
|
-
);
|
|
174
|
+
this.tracking.init(this.id);
|
|
172
175
|
} catch (e) {
|
|
173
176
|
console.info(
|
|
174
177
|
`Error initialising tracking on <custom-code-component> ${path}@${componentVersionRange}`
|
package/src/tracking.ts
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import Delegate from "ftdomdelegate";
|
|
2
|
+
import oTracking from "@financial-times/o-tracking";
|
|
3
|
+
import { getTrace } from "./get-trace";
|
|
4
|
+
import {
|
|
5
|
+
sanitise,
|
|
6
|
+
assignIfUndefined,
|
|
7
|
+
} from "@financial-times/o-tracking/src/javascript/utils.js";
|
|
8
|
+
|
|
9
|
+
const eventPropertiesToCollect = ["ctrlKey", "altKey", "shiftKey", "metaKey"];
|
|
10
|
+
|
|
11
|
+
class Tracking {
|
|
12
|
+
cccId: string;
|
|
13
|
+
cccName: string;
|
|
14
|
+
subtype: string;
|
|
15
|
+
teamName: string;
|
|
16
|
+
shadowRoot: ShadowRoot | null;
|
|
17
|
+
category: string;
|
|
18
|
+
elements: string | string[];
|
|
19
|
+
isInitialised: boolean;
|
|
20
|
+
|
|
21
|
+
constructor({
|
|
22
|
+
id = "00000000-0000-0000-0000-000000000000",
|
|
23
|
+
name = "ccc-component",
|
|
24
|
+
subtype = "interactive",
|
|
25
|
+
teamName = "djd",
|
|
26
|
+
shadowRoot = null,
|
|
27
|
+
category = "cta",
|
|
28
|
+
elements = 'a, button, input, [role="button"]',
|
|
29
|
+
} = {}) {
|
|
30
|
+
this.cccId = id;
|
|
31
|
+
this.cccName = name;
|
|
32
|
+
this.subtype = subtype;
|
|
33
|
+
this.teamName = teamName;
|
|
34
|
+
this.shadowRoot = shadowRoot;
|
|
35
|
+
this.category = category;
|
|
36
|
+
this.elements = elements;
|
|
37
|
+
this.isInitialised = false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Get properties for the event (as opposed to properties of the clicked element)
|
|
41
|
+
getEventProperties(event) {
|
|
42
|
+
const eventProperties = {};
|
|
43
|
+
for (const property of eventPropertiesToCollect) {
|
|
44
|
+
if (event[property]) {
|
|
45
|
+
try {
|
|
46
|
+
eventProperties[property] = sanitise(event[property]);
|
|
47
|
+
} catch (e) {
|
|
48
|
+
console.log(e);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return eventProperties;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Controller for handling click events
|
|
56
|
+
handleClickEvent(eventData, root) {
|
|
57
|
+
return (clickEvent, clickElement) => {
|
|
58
|
+
const context: any = this.getEventProperties(clickEvent);
|
|
59
|
+
const { trace, customContext } = getTrace(clickElement, root);
|
|
60
|
+
context.custom =
|
|
61
|
+
clickElement.dataset && clickElement.dataset.custom
|
|
62
|
+
? JSON.parse(clickElement.dataset.custom)
|
|
63
|
+
: null;
|
|
64
|
+
context.domPathTokens = trace;
|
|
65
|
+
context.component = {
|
|
66
|
+
id: this.cccId,
|
|
67
|
+
name: this.cccName,
|
|
68
|
+
type: "custom-code-component",
|
|
69
|
+
subtype: this.subtype,
|
|
70
|
+
};
|
|
71
|
+
context.teamName = this.teamName;
|
|
72
|
+
|
|
73
|
+
assignIfUndefined(customContext, context);
|
|
74
|
+
|
|
75
|
+
eventData.context = context;
|
|
76
|
+
eventData.method = "ftCustomAnalytics";
|
|
77
|
+
|
|
78
|
+
// send spoor event
|
|
79
|
+
document.body.dispatchEvent(
|
|
80
|
+
new CustomEvent("oTracking.event", {
|
|
81
|
+
detail: eventData,
|
|
82
|
+
bubbles: true,
|
|
83
|
+
composed: true,
|
|
84
|
+
})
|
|
85
|
+
);
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
sendSpoorEvent(triggerAction, extraDetail) {
|
|
90
|
+
const eventData = {
|
|
91
|
+
category: "component",
|
|
92
|
+
action: "act",
|
|
93
|
+
context: {
|
|
94
|
+
component: {
|
|
95
|
+
id: this.cccId,
|
|
96
|
+
name: this.cccName,
|
|
97
|
+
type: "custom-code-component",
|
|
98
|
+
subtype: this.subtype,
|
|
99
|
+
},
|
|
100
|
+
teamName: this.teamName,
|
|
101
|
+
trigger_action: triggerAction,
|
|
102
|
+
custom: extraDetail,
|
|
103
|
+
},
|
|
104
|
+
method: "ftCustomAnalytics",
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// send spoor event
|
|
108
|
+
document.body.dispatchEvent(
|
|
109
|
+
new CustomEvent("oTracking.event", {
|
|
110
|
+
detail: eventData,
|
|
111
|
+
bubbles: true,
|
|
112
|
+
composed: true,
|
|
113
|
+
})
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
init(id) {
|
|
118
|
+
if (!this.isInitialised) {
|
|
119
|
+
this.isInitialised = true;
|
|
120
|
+
this.cccId = id ? id : this.cccId;
|
|
121
|
+
|
|
122
|
+
oTracking.init({ queue: true, test: true }); // @TODO: Flip this to false before using in production
|
|
123
|
+
|
|
124
|
+
const eventData = {
|
|
125
|
+
action: "click",
|
|
126
|
+
category: this.category,
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const root = this.shadowRoot?.querySelector("#component-root");
|
|
130
|
+
|
|
131
|
+
if (this.shadowRoot) {
|
|
132
|
+
const shadowDelegate = new Delegate(root);
|
|
133
|
+
|
|
134
|
+
shadowDelegate.on(
|
|
135
|
+
"click",
|
|
136
|
+
this.elements,
|
|
137
|
+
this.handleClickEvent(eventData, root),
|
|
138
|
+
true
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export default Tracking;
|
package/dist/analytics.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
declare function sendSpoorEvent(triggerAction: any, extraDetail: any): void;
|
|
2
|
-
declare function init(templateObj: {
|
|
3
|
-
id?: string;
|
|
4
|
-
subtype?: string;
|
|
5
|
-
}, shadowRoot?: ShadowRoot, category?: string, elements?: []): void;
|
|
6
|
-
declare const tracking: {
|
|
7
|
-
init: typeof init;
|
|
8
|
-
isInitialised: boolean;
|
|
9
|
-
sendSpoorEvent: typeof sendSpoorEvent;
|
|
10
|
-
};
|
|
11
|
-
export default tracking;
|
package/src/analytics.ts
DELETED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
import Delegate from "ftdomdelegate";
|
|
2
|
-
import oTracking from "@financial-times/o-tracking";
|
|
3
|
-
import { getTrace } from "./get-trace";
|
|
4
|
-
import {
|
|
5
|
-
sanitise,
|
|
6
|
-
assignIfUndefined,
|
|
7
|
-
} from "@financial-times/o-tracking/src/javascript/utils.js";
|
|
8
|
-
|
|
9
|
-
// default values if nothing is passed into init
|
|
10
|
-
let cccName = "ccc-component";
|
|
11
|
-
let subtype = "interactive";
|
|
12
|
-
|
|
13
|
-
const eventPropertiesToCollect = ["ctrlKey", "altKey", "shiftKey", "metaKey"];
|
|
14
|
-
|
|
15
|
-
// Get properties for the event (as opposed to properties of the clicked element)
|
|
16
|
-
// Available properties include mouse x- and y co-ordinates, for example.
|
|
17
|
-
const getEventProperties = (event) => {
|
|
18
|
-
const eventProperties = {};
|
|
19
|
-
for (const property of eventPropertiesToCollect) {
|
|
20
|
-
if (event[property]) {
|
|
21
|
-
try {
|
|
22
|
-
eventProperties[property] = sanitise(event[property]);
|
|
23
|
-
} catch (e) {
|
|
24
|
-
// eslint-disable-next-line no-console
|
|
25
|
-
console.log(e);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return eventProperties;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
// Controller for handling click events
|
|
34
|
-
const handleClickEvent = (eventData, root) => (clickEvent, clickElement) => {
|
|
35
|
-
const context = getEventProperties(clickEvent);
|
|
36
|
-
const { trace, customContext } = getTrace(clickElement, root);
|
|
37
|
-
context.custom =
|
|
38
|
-
clickElement.dataset && clickElement.dataset.custom
|
|
39
|
-
? JSON.parse(clickElement.dataset.custom)
|
|
40
|
-
: null;
|
|
41
|
-
context.domPathTokens = trace;
|
|
42
|
-
context.component = {
|
|
43
|
-
id: cccName,
|
|
44
|
-
name: cccName,
|
|
45
|
-
type: "custom-code-component",
|
|
46
|
-
subtype,
|
|
47
|
-
};
|
|
48
|
-
context.teamName = "djd";
|
|
49
|
-
|
|
50
|
-
assignIfUndefined(customContext, context);
|
|
51
|
-
|
|
52
|
-
eventData.context = context;
|
|
53
|
-
eventData.method = "ftCustomAnalytics";
|
|
54
|
-
|
|
55
|
-
// send spoor event
|
|
56
|
-
document.body.dispatchEvent(
|
|
57
|
-
new CustomEvent("oTracking.event", {
|
|
58
|
-
detail: eventData,
|
|
59
|
-
bubbles: true,
|
|
60
|
-
composed: true,
|
|
61
|
-
})
|
|
62
|
-
);
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
function sendSpoorEvent(triggerAction, extraDetail) {
|
|
66
|
-
const eventData = {
|
|
67
|
-
category: "component",
|
|
68
|
-
action: "act",
|
|
69
|
-
context: {
|
|
70
|
-
component: {
|
|
71
|
-
id: cccName,
|
|
72
|
-
name: cccName,
|
|
73
|
-
type: "custom-code-component",
|
|
74
|
-
subtype,
|
|
75
|
-
},
|
|
76
|
-
teamName: "djd",
|
|
77
|
-
trigger_action: triggerAction,
|
|
78
|
-
custom: extraDetail,
|
|
79
|
-
},
|
|
80
|
-
method: "ftCustomAnalytics",
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
// send spoor event
|
|
84
|
-
document.body.dispatchEvent(
|
|
85
|
-
new CustomEvent("oTracking.event", {
|
|
86
|
-
detail: eventData,
|
|
87
|
-
bubbles: true,
|
|
88
|
-
composed: true,
|
|
89
|
-
})
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function init(
|
|
94
|
-
templateObj: { id?: string; subtype?: string },
|
|
95
|
-
shadowRoot?: ShadowRoot,
|
|
96
|
-
category?: string,
|
|
97
|
-
elements?: []
|
|
98
|
-
) {
|
|
99
|
-
if (!tracking.isInitialised) {
|
|
100
|
-
tracking.isInitialised = true;
|
|
101
|
-
if (templateObj) {
|
|
102
|
-
cccName = templateObj.id || cccName;
|
|
103
|
-
subtype = templateObj.subtype || subtype;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
oTracking.init({ queue: true, test: true }); // @TODO: Flip this to false before using in production
|
|
107
|
-
|
|
108
|
-
const elementsToTrack = elements || 'a, button, input, [role="button"]';
|
|
109
|
-
|
|
110
|
-
// Note: `context` is the term o-tracking uses for the data that is sent to spoor
|
|
111
|
-
const eventData = {
|
|
112
|
-
action: "click",
|
|
113
|
-
category: category || "cta",
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
const root = shadowRoot?.querySelector("#component-root");
|
|
117
|
-
|
|
118
|
-
if (shadowRoot) {
|
|
119
|
-
const shadowDelegate = new Delegate(root);
|
|
120
|
-
|
|
121
|
-
shadowDelegate.on(
|
|
122
|
-
"click",
|
|
123
|
-
elementsToTrack,
|
|
124
|
-
handleClickEvent(eventData, root),
|
|
125
|
-
true
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const tracking = {
|
|
132
|
-
init,
|
|
133
|
-
isInitialised: false,
|
|
134
|
-
sendSpoorEvent,
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
export default tracking;
|