@financial-times/custom-code-component 2.0.14 → 2.0.16
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-element.d.ts +115 -2
- package/dist/custom-element.js +214 -126
- package/dist/custom-element.js.map +1 -1
- package/package.json +1 -1
- package/src/custom-code-component.ts +157 -9
- package/src/logger.ts +20 -6
package/dist/custom-element.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
function
|
|
2
|
-
this.listenerMap = [{}, {}], o && this.root(o), this.handle =
|
|
1
|
+
function m(o) {
|
|
2
|
+
this.listenerMap = [{}, {}], o && this.root(o), this.handle = m.prototype.handle.bind(this), this._removedListeners = [];
|
|
3
3
|
}
|
|
4
|
-
|
|
4
|
+
m.prototype.root = function(o) {
|
|
5
5
|
const t = this.listenerMap;
|
|
6
6
|
let e;
|
|
7
7
|
if (this.rootElement) {
|
|
@@ -19,23 +19,23 @@ l.prototype.root = function(o) {
|
|
|
19
19
|
t[0].hasOwnProperty(e) && this.rootElement.addEventListener(e, this.handle, !1);
|
|
20
20
|
return this;
|
|
21
21
|
};
|
|
22
|
-
|
|
22
|
+
m.prototype.captureForType = function(o) {
|
|
23
23
|
return ["blur", "error", "focus", "load", "resize", "scroll"].indexOf(o) !== -1;
|
|
24
24
|
};
|
|
25
|
-
|
|
25
|
+
m.prototype.on = function(o, t, e, n) {
|
|
26
26
|
let r, s, i, c;
|
|
27
27
|
if (!o)
|
|
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 = U) : /^#[a-z0-9\-_]+$/i.test(t) ? (c = t.slice(1), i = D) : (c = t, i = Element.prototype.matches) : (c = null, i = _.bind(this)), s[o].push({
|
|
32
32
|
selector: t,
|
|
33
33
|
handler: e,
|
|
34
34
|
matcher: i,
|
|
35
35
|
matcherParam: c
|
|
36
36
|
}), this;
|
|
37
37
|
};
|
|
38
|
-
|
|
38
|
+
m.prototype.off = function(o, t, e, n) {
|
|
39
39
|
let r, s, i, c, a;
|
|
40
40
|
if (typeof t == "function" && (n = e, e = t, t = null), n === void 0)
|
|
41
41
|
return this.off(o, t, e, !0), this.off(o, t, e, !1), this;
|
|
@@ -50,12 +50,12 @@ l.prototype.off = function(o, t, e, n) {
|
|
|
50
50
|
s = c[r], (!t || t === s.selector) && (!e || e === s.handler) && (this._removedListeners.push(s), c.splice(r, 1));
|
|
51
51
|
return c.length || (delete i[o], this.rootElement && this.rootElement.removeEventListener(o, this.handle, n)), this;
|
|
52
52
|
};
|
|
53
|
-
|
|
53
|
+
m.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 l = "ftLabsDelegateIgnore";
|
|
58
|
+
if (o[l] === !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:
|
|
@@ -75,21 +75,21 @@ l.prototype.handle = function(o) {
|
|
|
75
75
|
if (h === r || (e = a.length, h = h.parentElement || h.parentNode, h instanceof HTMLDocument))
|
|
76
76
|
break;
|
|
77
77
|
}
|
|
78
|
-
let
|
|
78
|
+
let $;
|
|
79
79
|
for (t = 0; t < u.length; t++)
|
|
80
80
|
if (!(this._removedListeners.indexOf(u[t][2]) > -1) && (c = this.fire.apply(this, u[t]), c === !1)) {
|
|
81
|
-
u[t][0][
|
|
81
|
+
u[t][0][l] = !0, u[t][0].preventDefault(), $ = !1;
|
|
82
82
|
break;
|
|
83
83
|
}
|
|
84
|
-
return
|
|
84
|
+
return $;
|
|
85
85
|
};
|
|
86
|
-
|
|
86
|
+
m.prototype.fire = function(o, t, e) {
|
|
87
87
|
return e.handler.call(t, o, t);
|
|
88
88
|
};
|
|
89
|
-
function
|
|
89
|
+
function U(o, t) {
|
|
90
90
|
return o.toLowerCase() === t.tagName.toLowerCase();
|
|
91
91
|
}
|
|
92
|
-
function
|
|
92
|
+
function _(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,48 +97,51 @@ function U(o, t) {
|
|
|
97
97
|
t === window
|
|
98
98
|
) : this.rootElement === t;
|
|
99
99
|
}
|
|
100
|
-
function
|
|
100
|
+
function D(o, t) {
|
|
101
101
|
return o === t.id;
|
|
102
102
|
}
|
|
103
|
-
|
|
103
|
+
m.prototype.destroy = function() {
|
|
104
104
|
this.off(), this.root();
|
|
105
105
|
};
|
|
106
|
-
function
|
|
106
|
+
function N(o) {
|
|
107
107
|
return typeof o == "string" ? o.trim() : o;
|
|
108
108
|
}
|
|
109
|
-
function
|
|
109
|
+
function I(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 p = Object.freeze({
|
|
114
114
|
DEBUG: 0,
|
|
115
115
|
INFO: 1,
|
|
116
116
|
WARN: 2,
|
|
117
117
|
ERROR: 3,
|
|
118
118
|
TEST: 4,
|
|
119
119
|
DEFAULT: 2
|
|
120
|
-
});
|
|
121
|
-
function
|
|
120
|
+
}), b = "CCC:";
|
|
121
|
+
function S(o) {
|
|
122
122
|
const t = o == null ? void 0 : o.toLowerCase();
|
|
123
|
-
return t === "debug" ?
|
|
123
|
+
return t === "debug" ? p.DEBUG : t === "info" ? p.INFO : t === "warn" ? p.WARN : t === "error" ? p.ERROR : t === "test" ? p.TEST : p.DEFAULT;
|
|
124
124
|
}
|
|
125
|
-
class
|
|
126
|
-
constructor({ level: t =
|
|
127
|
-
level:
|
|
125
|
+
class P {
|
|
126
|
+
constructor({ level: t = p.DEFAULT } = {
|
|
127
|
+
level: p.DEFAULT
|
|
128
128
|
}) {
|
|
129
|
-
this.log = this.debug, this.level = t;
|
|
129
|
+
this.log = this.debug, this.level = localStorage.getItem("CCC_LOG_LEVEL") ? S(localStorage.getItem("CCC_LOG_LEVEL")) : t;
|
|
130
130
|
}
|
|
131
131
|
debug(...t) {
|
|
132
|
-
this.level <=
|
|
132
|
+
this.level <= p.DEBUG && console.info(b, ...t);
|
|
133
133
|
}
|
|
134
134
|
info(...t) {
|
|
135
|
-
this.level <=
|
|
135
|
+
this.level <= p.INFO && console.info(b, ...t);
|
|
136
136
|
}
|
|
137
137
|
warn(...t) {
|
|
138
|
-
this.level <=
|
|
138
|
+
this.level <= p.WARN && console.warn(b, ...t);
|
|
139
139
|
}
|
|
140
140
|
error(...t) {
|
|
141
|
-
this.level <=
|
|
141
|
+
this.level <= p.ERROR && console.error(b, ...t);
|
|
142
|
+
}
|
|
143
|
+
setLogLevel(t) {
|
|
144
|
+
localStorage.getItem("CCC_LOG_LEVEL") ? this.level = S(localStorage.getItem("CCC_LOG_LEVEL")) : typeof t == "number" ? this.level = t : this.level = S(t);
|
|
142
145
|
}
|
|
143
146
|
}
|
|
144
147
|
const M = (o, t, e) => {
|
|
@@ -155,51 +158,51 @@ const M = (o, t, e) => {
|
|
|
155
158
|
"href",
|
|
156
159
|
"text",
|
|
157
160
|
"role"
|
|
158
|
-
],
|
|
161
|
+
], F = (o) => {
|
|
159
162
|
const t = {};
|
|
160
163
|
for (const e of x) {
|
|
161
164
|
const n = o[e] || o.getAttribute(e) || o.hasAttribute(e);
|
|
162
|
-
n !== void 0 && (typeof n == "boolean" ? t[e] = n : t[e] =
|
|
165
|
+
n !== void 0 && (typeof n == "boolean" ? t[e] = n : t[e] = N(n));
|
|
163
166
|
}
|
|
164
167
|
return t;
|
|
165
|
-
},
|
|
168
|
+
}, j = (o) => {
|
|
166
169
|
try {
|
|
167
170
|
const t = JSON.parse(o), e = Object.prototype.toString.call(t);
|
|
168
171
|
return [e === "[object Object]" || e === "[object Array]", t];
|
|
169
172
|
} catch {
|
|
170
173
|
return [!1, null];
|
|
171
174
|
}
|
|
172
|
-
},
|
|
173
|
-
const [t, e] =
|
|
175
|
+
}, H = (o) => {
|
|
176
|
+
const [t, e] = j(o);
|
|
174
177
|
return t ? e : o;
|
|
175
|
-
},
|
|
178
|
+
}, V = (o, t) => (o.filter(
|
|
176
179
|
(e) => e.name.match(/^data-trackable|^data-o-|^aria-/i)
|
|
177
180
|
).forEach((e) => {
|
|
178
181
|
t[e.name] = e.value;
|
|
179
|
-
}), t),
|
|
182
|
+
}), t), Y = (o, t, e) => {
|
|
180
183
|
const n = {};
|
|
181
184
|
return e && x.forEach((r) => {
|
|
182
185
|
typeof t[r] < "u" && r !== "id" && (n[r] = t[r]);
|
|
183
186
|
}), o.filter((r) => r.name.match(/^data-trackable-context-/i)).forEach((r) => {
|
|
184
|
-
n[r.name.replace("data-trackable-context-", "")] =
|
|
187
|
+
n[r.name.replace("data-trackable-context-", "")] = H(r.value);
|
|
185
188
|
}), n;
|
|
186
189
|
};
|
|
187
|
-
function
|
|
190
|
+
function z(o, t) {
|
|
188
191
|
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
192
|
for (; o && o !== t; ) {
|
|
190
|
-
const i =
|
|
191
|
-
let a =
|
|
193
|
+
const i = F(o), c = Array.from(o.attributes);
|
|
194
|
+
let a = V(c, i);
|
|
192
195
|
a["data-trackable"] && (a = Object.assign(
|
|
193
196
|
a,
|
|
194
197
|
M(o, e, n)
|
|
195
198
|
)), r.push(a);
|
|
196
|
-
const h =
|
|
197
|
-
|
|
199
|
+
const h = Y(c, i, o === e);
|
|
200
|
+
I(h, s), o = o.parentNode;
|
|
198
201
|
}
|
|
199
202
|
return { trace: r, customContext: s };
|
|
200
203
|
}
|
|
201
|
-
const
|
|
202
|
-
class
|
|
204
|
+
const q = ["ctrlKey", "altKey", "shiftKey", "metaKey"];
|
|
205
|
+
class G {
|
|
203
206
|
constructor({
|
|
204
207
|
id: t = "00000000-0000-0000-0000-000000000000",
|
|
205
208
|
name: e = "ccc-component",
|
|
@@ -210,15 +213,15 @@ class Y {
|
|
|
210
213
|
elements: c = 'a, button, input, [role="button"]',
|
|
211
214
|
logger: a
|
|
212
215
|
}) {
|
|
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
|
|
216
|
+
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 P();
|
|
214
217
|
}
|
|
215
218
|
// Get properties for the event (as opposed to properties of the clicked element)
|
|
216
219
|
getEventProperties(t) {
|
|
217
220
|
const e = {};
|
|
218
|
-
for (const n of
|
|
221
|
+
for (const n of q)
|
|
219
222
|
if (t[n])
|
|
220
223
|
try {
|
|
221
|
-
e[n] =
|
|
224
|
+
e[n] = N(t[n]);
|
|
222
225
|
} catch (r) {
|
|
223
226
|
this.log.info(r);
|
|
224
227
|
}
|
|
@@ -227,13 +230,13 @@ class Y {
|
|
|
227
230
|
// Controller for handling click events
|
|
228
231
|
handleClickEvent(t, e) {
|
|
229
232
|
return (n, r) => {
|
|
230
|
-
const s = this.getEventProperties(n), { trace: i, customContext: c } =
|
|
233
|
+
const s = this.getEventProperties(n), { trace: i, customContext: c } = z(r, e);
|
|
231
234
|
s.custom = r.dataset && r.dataset.custom ? JSON.parse(r.dataset.custom) : null, s.domPathTokens = i, s.component = {
|
|
232
235
|
id: this.cccId,
|
|
233
236
|
name: this.cccName,
|
|
234
237
|
type: "custom-code-component",
|
|
235
238
|
subtype: this.subtype
|
|
236
|
-
}, s.teamName = this.teamName, s.url = document.URL,
|
|
239
|
+
}, s.teamName = this.teamName, s.url = document.URL, I(c, s), s.method = "ftCustomAnalytics", t = { ...t, ...s }, document.body.dispatchEvent(
|
|
237
240
|
new CustomEvent("oTracking.event", {
|
|
238
241
|
detail: t,
|
|
239
242
|
bubbles: !0,
|
|
@@ -273,7 +276,7 @@ class Y {
|
|
|
273
276
|
action: "click",
|
|
274
277
|
category: this.category
|
|
275
278
|
}, r = (e = this.shadowRoot) == null ? void 0 : e.querySelector("[data-component-root]");
|
|
276
|
-
r && new
|
|
279
|
+
r && new m(r).on(
|
|
277
280
|
"click",
|
|
278
281
|
this.elements,
|
|
279
282
|
this.handleClickEvent(n, r),
|
|
@@ -282,14 +285,14 @@ class Y {
|
|
|
282
285
|
}
|
|
283
286
|
}
|
|
284
287
|
}
|
|
285
|
-
class
|
|
288
|
+
class d {
|
|
286
289
|
constructor(t) {
|
|
287
290
|
this.org = "local", this.repo = "dev";
|
|
288
|
-
const { org: e, repo: n, name: r, versionRange: s } =
|
|
291
|
+
const { org: e, repo: n, name: r, versionRange: s } = L(t) ? t : d.fromString(t);
|
|
289
292
|
e && (this.org = e), n && (this.repo = n), this.name = r, this.versionRange = s;
|
|
290
293
|
}
|
|
291
294
|
set path(t) {
|
|
292
|
-
const { org: e, repo: n, name: r, versionRange: s } =
|
|
295
|
+
const { org: e, repo: n, name: r, versionRange: s } = L(t) ? t : d.fromString(t);
|
|
293
296
|
this.org = e, this.repo = n, this.name = r, this.versionRange = s;
|
|
294
297
|
}
|
|
295
298
|
get path() {
|
|
@@ -306,42 +309,42 @@ class f {
|
|
|
306
309
|
static fromString(t, e) {
|
|
307
310
|
var a;
|
|
308
311
|
const n = t ?? "unknown/unknown/unknown", [r, s, i] = n.replace(/@[^\/]+/, "").split("/").reverse(), c = e ?? ((a = n.match(/@[^\/]+/)) == null ? void 0 : a.toString().replace("@", "")) ?? "unknown";
|
|
309
|
-
if (s && !c) throw new
|
|
310
|
-
return new
|
|
312
|
+
if (s && !c) throw new f("No version specified");
|
|
313
|
+
return new d({ org: i, repo: s, name: r, versionRange: c });
|
|
311
314
|
}
|
|
312
315
|
}
|
|
313
|
-
function
|
|
316
|
+
function L(o) {
|
|
314
317
|
return typeof o == "object" && o !== null ? "org" in o && "repo" in o && "name" in o : !1;
|
|
315
318
|
}
|
|
316
|
-
class
|
|
319
|
+
class f extends Error {
|
|
317
320
|
constructor(t, e) {
|
|
318
321
|
var n;
|
|
319
322
|
!e && t ? (super(t), this.component = null) : typeof (e == null ? void 0 : e.component) == "string" ? (super(
|
|
320
323
|
t ?? `${e.cause ?? "Unknown error"} in ${e.component} imported from ${e.source ?? "an undefined source"}.`
|
|
321
|
-
), this.component =
|
|
324
|
+
), this.component = d.fromString(e.component)) : L(e == null ? void 0 : e.component) ? (super(
|
|
322
325
|
t ?? `${e.cause ?? "Unknown error"} in ${e.component.org}/${e.component.repo}/${e.component.name}@${e.component.versionRange} imported from ${e.source ?? "an undefined source"}.`
|
|
323
|
-
), this.component = new
|
|
326
|
+
), this.component = new d(e.component)) : (super(
|
|
324
327
|
`${(e == null ? void 0 : e.cause) ?? "Unknown error"} in unknown component imported from ${(e == null ? void 0 : e.source) ?? "unknown source"}.`
|
|
325
|
-
), this.component = null), this.source = (e == null ? void 0 : e.source) ?? "unknown source", this.errors = [], e != null && e.error && ((n = this.errors) == null || n.push(e == null ? void 0 : e.error)), Error.captureStackTrace && Error.captureStackTrace(this,
|
|
328
|
+
), this.component = null), this.source = (e == null ? void 0 : e.source) ?? "unknown source", this.errors = [], e != null && e.error && ((n = this.errors) == null || n.push(e == null ? void 0 : e.error)), Error.captureStackTrace && Error.captureStackTrace(this, f), this.name = "CCCError";
|
|
326
329
|
}
|
|
327
330
|
}
|
|
328
|
-
class w extends
|
|
331
|
+
class w extends f {
|
|
329
332
|
constructor(t, e) {
|
|
330
333
|
super(t, { ...e, cause: "Import error" }), this.name = "CCCImportError";
|
|
331
334
|
}
|
|
332
335
|
}
|
|
333
|
-
class
|
|
336
|
+
class O extends f {
|
|
334
337
|
constructor(t, e) {
|
|
335
338
|
super(t, { ...e, cause: "Render error" }), this.name = "CCCRenderError";
|
|
336
339
|
}
|
|
337
340
|
}
|
|
338
|
-
class J extends
|
|
341
|
+
class J extends f {
|
|
339
342
|
constructor(t) {
|
|
340
343
|
super(null, { ...t, cause: "Timeout error" }), this.name = "CCCTimeoutError";
|
|
341
344
|
}
|
|
342
345
|
}
|
|
343
|
-
const
|
|
344
|
-
constructor(t =
|
|
346
|
+
const E = class E extends Event {
|
|
347
|
+
constructor(t = E.eventType, e, n) {
|
|
345
348
|
super(t, {
|
|
346
349
|
bubbles: !0,
|
|
347
350
|
cancelable: !1,
|
|
@@ -350,48 +353,48 @@ const b = class b extends Event {
|
|
|
350
353
|
}), this.component = e.component, this.source = e.source;
|
|
351
354
|
}
|
|
352
355
|
};
|
|
353
|
-
|
|
354
|
-
let g =
|
|
355
|
-
const E = class E extends g {
|
|
356
|
-
constructor(t, e) {
|
|
357
|
-
super(E.eventType, t, e);
|
|
358
|
-
}
|
|
359
|
-
};
|
|
360
|
-
E.eventType = "ccc:connected";
|
|
361
|
-
let T = E;
|
|
356
|
+
E.eventType = "ccc:event";
|
|
357
|
+
let g = E;
|
|
362
358
|
const y = class y extends g {
|
|
363
359
|
constructor(t, e) {
|
|
364
360
|
super(y.eventType, t, e);
|
|
365
361
|
}
|
|
366
362
|
};
|
|
367
|
-
y.eventType = "ccc:
|
|
368
|
-
let
|
|
363
|
+
y.eventType = "ccc:connected";
|
|
364
|
+
let T = y;
|
|
369
365
|
const v = class v extends g {
|
|
370
366
|
constructor(t, e) {
|
|
371
|
-
super(v.eventType, t, e)
|
|
367
|
+
super(v.eventType, t, e);
|
|
372
368
|
}
|
|
373
369
|
};
|
|
374
|
-
v.eventType = "ccc:
|
|
375
|
-
let
|
|
370
|
+
v.eventType = "ccc:ready";
|
|
371
|
+
let k = v;
|
|
372
|
+
const C = class C extends g {
|
|
373
|
+
constructor(t, e) {
|
|
374
|
+
super(C.eventType, t, e), this.intersecting = !1, this.intersecting = t.intersecting, this.entry = t.entry;
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
C.eventType = "ccc:viewport";
|
|
378
|
+
let R = C;
|
|
376
379
|
const W = (o) => o.replace(
|
|
377
380
|
/[A-Z]+(?![a-z])|[A-Z]/g,
|
|
378
381
|
(t, e) => (e ? "-" : "") + t.toLowerCase()
|
|
379
382
|
);
|
|
380
|
-
function
|
|
383
|
+
function K(o) {
|
|
381
384
|
return A([
|
|
382
385
|
"localhost",
|
|
383
386
|
"local.ft.com",
|
|
384
387
|
/^.*\.apps\.in\.ft\.com$/
|
|
385
388
|
], o);
|
|
386
389
|
}
|
|
387
|
-
function
|
|
390
|
+
function B() {
|
|
388
391
|
return A([
|
|
389
392
|
"localhost",
|
|
390
393
|
"local.ft.com",
|
|
391
394
|
/^.*\.in\.ft\.com$/
|
|
392
395
|
], window.location.hostname);
|
|
393
396
|
}
|
|
394
|
-
function
|
|
397
|
+
function Z() {
|
|
395
398
|
return A([
|
|
396
399
|
"spark.ft.com",
|
|
397
400
|
"spark-staging.ft.com"
|
|
@@ -400,18 +403,18 @@ function B() {
|
|
|
400
403
|
function A(o, t) {
|
|
401
404
|
return t ? o.some((e) => typeof e == "string" ? e === t : e.test(t)) : !1;
|
|
402
405
|
}
|
|
403
|
-
function
|
|
406
|
+
function X(o) {
|
|
404
407
|
if (o === null)
|
|
405
408
|
return;
|
|
406
409
|
let t;
|
|
407
410
|
const e = new URL("http://localhost:5173");
|
|
408
411
|
try {
|
|
409
412
|
if (typeof o == "string") {
|
|
410
|
-
if ((o === "" || o.toLowerCase() === "true") &&
|
|
413
|
+
if ((o === "" || o.toLowerCase() === "true") && B())
|
|
411
414
|
t = e;
|
|
412
|
-
else if (t = o.startsWith("http://") || o.startsWith("https://") ? new URL(o) : void 0, t && !
|
|
415
|
+
else if (t = o.startsWith("http://") || o.startsWith("https://") ? new URL(o) : void 0, t && !K(t == null ? void 0 : t.hostname))
|
|
413
416
|
throw new Error("Unsafe testing host override");
|
|
414
|
-
} else
|
|
417
|
+
} else Z() && (t = e);
|
|
415
418
|
} catch {
|
|
416
419
|
return t;
|
|
417
420
|
}
|
|
@@ -425,8 +428,14 @@ async function Q(o, t) {
|
|
|
425
428
|
}
|
|
426
429
|
).then(() => !0).catch(() => !1) : !1;
|
|
427
430
|
}
|
|
428
|
-
const
|
|
429
|
-
class
|
|
431
|
+
const tt = ":host{width:var(--ccc-root-width, 100%);margin:var(--ccc-root-margin);padding:var(--ccc-root-padding);display:var(--ccc-root-display, block);font-size:var(--ccc-root-fontSize);box-sizing:var(--ccc-root-boxSizing);border:var(--ccc-root-border);grid:var(--ccc-root-grid);line-height:var(--ccc-root-lineHeight)}";
|
|
432
|
+
class et extends HTMLElement {
|
|
433
|
+
/**
|
|
434
|
+
* Custom Element constructor.
|
|
435
|
+
*
|
|
436
|
+
* n.b., attributes and ShadowDOM aren't available in custom element constructors.
|
|
437
|
+
* Use connectedCallback() and other lifecycle methods if you want to eg. this.getAttribute()
|
|
438
|
+
*/
|
|
430
439
|
constructor() {
|
|
431
440
|
super(), this.mode = "open", this.RESERVED_ATTRS = /* @__PURE__ */ new Set([
|
|
432
441
|
"iframe",
|
|
@@ -437,8 +446,8 @@ class tt extends HTMLElement {
|
|
|
437
446
|
"shadow-open",
|
|
438
447
|
"env",
|
|
439
448
|
"load-timeout"
|
|
440
|
-
]), this.component = new
|
|
441
|
-
e.forEach((n) => {
|
|
449
|
+
]), this.component = new d(), this.observer = new IntersectionObserver((e) => {
|
|
450
|
+
this.log.debug("Intersection Observer callback", { entries: e }), e.forEach((n) => {
|
|
442
451
|
this.dispatchEvent(
|
|
443
452
|
new R({
|
|
444
453
|
component: this.component,
|
|
@@ -450,6 +459,7 @@ class tt extends HTMLElement {
|
|
|
450
459
|
});
|
|
451
460
|
}), this.channel = new MessageChannel(), this.initTracking = async () => {
|
|
452
461
|
var e;
|
|
462
|
+
this.log.debug("initTracking", { cccId: this.id });
|
|
453
463
|
try {
|
|
454
464
|
(e = this.tracking) == null || e.init(this.id);
|
|
455
465
|
} catch (n) {
|
|
@@ -471,9 +481,7 @@ class tt extends HTMLElement {
|
|
|
471
481
|
`.trim(), document.head.appendChild(e);
|
|
472
482
|
const n = document.createElement("script");
|
|
473
483
|
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: D(this.getAttribute("log"))
|
|
476
|
-
});
|
|
484
|
+
}, this.log = new P();
|
|
477
485
|
const t = HTMLElement.prototype.hasOwnProperty("attachInternals");
|
|
478
486
|
try {
|
|
479
487
|
const e = t && this.attachInternals();
|
|
@@ -481,18 +489,29 @@ class tt extends HTMLElement {
|
|
|
481
489
|
this.log.error(e);
|
|
482
490
|
}
|
|
483
491
|
}
|
|
492
|
+
/**
|
|
493
|
+
* connectedCallback() CE lifecycle callback
|
|
494
|
+
*
|
|
495
|
+
* Called whenever a <custom-code-component> element is mounted to the DOM.
|
|
496
|
+
*/
|
|
484
497
|
async connectedCallback() {
|
|
485
498
|
try {
|
|
499
|
+
this.log.setLogLevel(this.getAttribute("log")), this.log.debug("connectedCallback");
|
|
486
500
|
const t = this.getAttribute("path"), e = this.getAttribute("version");
|
|
487
|
-
this.component =
|
|
501
|
+
this.component = d.fromString(t, e), this.app = await this.load(), await this.mount(), await this.initTracking();
|
|
488
502
|
} catch (t) {
|
|
489
503
|
t instanceof Error && requestAnimationFrame(() => {
|
|
490
504
|
this.emitError(t);
|
|
491
505
|
}), this.unmount(t);
|
|
492
506
|
}
|
|
493
507
|
}
|
|
508
|
+
/**
|
|
509
|
+
* Error handler. Decorates errors for easier ingestion.
|
|
510
|
+
*
|
|
511
|
+
* @param error
|
|
512
|
+
*/
|
|
494
513
|
emitError(t) {
|
|
495
|
-
if (
|
|
514
|
+
if (this.log.debug("emitError", { error: t }), t instanceof f)
|
|
496
515
|
this.dispatchEvent(
|
|
497
516
|
new ErrorEvent("ccc:error", {
|
|
498
517
|
bubbles: !0,
|
|
@@ -503,7 +522,7 @@ class tt extends HTMLElement {
|
|
|
503
522
|
})
|
|
504
523
|
);
|
|
505
524
|
else {
|
|
506
|
-
const e = new
|
|
525
|
+
const e = new f(t.message, {
|
|
507
526
|
component: this.component,
|
|
508
527
|
error: t
|
|
509
528
|
});
|
|
@@ -518,15 +537,33 @@ class tt extends HTMLElement {
|
|
|
518
537
|
);
|
|
519
538
|
}
|
|
520
539
|
}
|
|
540
|
+
/**
|
|
541
|
+
* disconnectedCallback() CE lifecycle event.
|
|
542
|
+
*
|
|
543
|
+
* Called when a <custom-code-component> element is removed from DOM.
|
|
544
|
+
*/
|
|
521
545
|
disconnectedCallback() {
|
|
546
|
+
this.log.debug("disconnectedCallback");
|
|
522
547
|
const t = this.getAttribute("path");
|
|
523
548
|
this.log.info(`<custom-code-component:${t}> disconnected`), this.observer.disconnect();
|
|
524
549
|
}
|
|
525
|
-
|
|
526
|
-
|
|
550
|
+
/**
|
|
551
|
+
* MessageChannel postMessage callback
|
|
552
|
+
*
|
|
553
|
+
* @param e
|
|
554
|
+
*/
|
|
555
|
+
onmessage(t) {
|
|
556
|
+
this.log.debug("onmessage", { event: t });
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* This error handler is called by the child component on e.g. unrecoverable error.
|
|
560
|
+
* It then calls unmount(), which restores the fallback.
|
|
561
|
+
*
|
|
562
|
+
* @param e
|
|
563
|
+
*/
|
|
527
564
|
onunmount(t) {
|
|
528
|
-
if (t instanceof Error) {
|
|
529
|
-
const e = new
|
|
565
|
+
if (this.log.debug("onunmount", { error: t }), t instanceof Error) {
|
|
566
|
+
const e = new O(t.message, {
|
|
530
567
|
error: t,
|
|
531
568
|
component: this.component
|
|
532
569
|
});
|
|
@@ -535,17 +572,23 @@ class tt extends HTMLElement {
|
|
|
535
572
|
});
|
|
536
573
|
}
|
|
537
574
|
}
|
|
575
|
+
/**
|
|
576
|
+
* onready event callback.
|
|
577
|
+
* Called by mount() after kicking off initial component render.
|
|
578
|
+
*
|
|
579
|
+
* @param app
|
|
580
|
+
*/
|
|
538
581
|
async onready(t) {
|
|
539
582
|
try {
|
|
540
|
-
await t, this.dispatchEvent(
|
|
583
|
+
await t, this.log.debug("onready", { app: t }), this.dispatchEvent(
|
|
541
584
|
new k({
|
|
542
585
|
component: this.component,
|
|
543
586
|
source: this.source
|
|
544
587
|
})
|
|
545
588
|
), this.dataset.cccReady = "true", delete this.dataset.cccError, this.observer.observe(this);
|
|
546
589
|
} catch (e) {
|
|
547
|
-
if (e instanceof Error) {
|
|
548
|
-
const n = new
|
|
590
|
+
if (this.log.debug("onready caught error", { error: e }), e instanceof Error) {
|
|
591
|
+
const n = new O(e.message, {
|
|
549
592
|
error: e,
|
|
550
593
|
component: this.component
|
|
551
594
|
});
|
|
@@ -555,11 +598,26 @@ class tt extends HTMLElement {
|
|
|
555
598
|
}
|
|
556
599
|
}
|
|
557
600
|
}
|
|
601
|
+
/**
|
|
602
|
+
* MessageChannel postMessage handler.
|
|
603
|
+
* This can be used for inter-CCC communication.
|
|
604
|
+
* @param event
|
|
605
|
+
*/
|
|
558
606
|
postMessage(t) {
|
|
559
|
-
this.channel.port1.postMessage(t);
|
|
560
|
-
}
|
|
607
|
+
this.log.debug("postmessage", { event: t }), this.channel.port1.postMessage(t);
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Initial mounting behaviour.
|
|
611
|
+
*
|
|
612
|
+
* Attaches ShadowDOM if needed, dispatches ccc:connected event, adds component base styles,
|
|
613
|
+
* generates fallback template element if one doesn't exist already, initialises tracking,
|
|
614
|
+
* then kicks off component rendering. Passes component render promise to onready().
|
|
615
|
+
*
|
|
616
|
+
* @param prerendered
|
|
617
|
+
*/
|
|
561
618
|
async mount(t) {
|
|
562
619
|
var e, n;
|
|
620
|
+
this.log.debug("mount", t);
|
|
563
621
|
try {
|
|
564
622
|
if (this.mode = this.getAttribute("shadow-open") == "false" ? "closed" : "open", this.component) {
|
|
565
623
|
if (!this.app)
|
|
@@ -570,16 +628,17 @@ class tt extends HTMLElement {
|
|
|
570
628
|
component: this.component,
|
|
571
629
|
source: this.source
|
|
572
630
|
})
|
|
573
|
-
), !s.querySelector('link[href~="custom-code-component.css"]') && !s.adoptedStyleSheets.length && (window.CCC_LAYOUT_STYLESHEET || (window.CCC_LAYOUT_STYLESHEET = new CSSStyleSheet(), window.CCC_LAYOUT_STYLESHEET.replaceSync(
|
|
574
|
-
|
|
575
|
-
|
|
631
|
+
), !s.querySelector('link[href~="custom-code-component.css"]') && !s.adoptedStyleSheets.length && (window.CCC_LAYOUT_STYLESHEET || (this.log.debug("mount generating CCC_LAYOUT_STYLESHEET"), window.CCC_LAYOUT_STYLESHEET = new CSSStyleSheet(), window.CCC_LAYOUT_STYLESHEET.replaceSync(tt)), s.adoptedStyleSheets = [window.CCC_LAYOUT_STYLESHEET]), !r) {
|
|
632
|
+
this.log.debug("mount generating fallback template");
|
|
633
|
+
const l = document.createElement("template");
|
|
634
|
+
l.innerHTML = "<div data-component-root><slot></slot></div>", this.appendChild(l), s.appendChild(l.content.cloneNode(!0));
|
|
576
635
|
}
|
|
577
636
|
const i = JSON.parse(this.getAttribute("data-component-props")), c = Object.fromEntries(
|
|
578
637
|
[...this.attributes].filter(
|
|
579
|
-
(
|
|
580
|
-
).map((
|
|
638
|
+
(l) => !this.RESERVED_ATTRS.has(l.name) && !l.name.startsWith("data-")
|
|
639
|
+
).map((l) => [l.name, l.value])
|
|
581
640
|
);
|
|
582
|
-
this.tracking = new
|
|
641
|
+
this.tracking = new G({
|
|
583
642
|
name: (e = this.component) == null ? void 0 : e.toString(),
|
|
584
643
|
subtype: "interactive",
|
|
585
644
|
teamName: "djd",
|
|
@@ -598,6 +657,7 @@ class tt extends HTMLElement {
|
|
|
598
657
|
s,
|
|
599
658
|
{
|
|
600
659
|
...i ?? c,
|
|
660
|
+
log: this.log,
|
|
601
661
|
data: i ?? c,
|
|
602
662
|
port: this.channel.port2,
|
|
603
663
|
tracking: this.tracking,
|
|
@@ -615,31 +675,41 @@ class tt extends HTMLElement {
|
|
|
615
675
|
), this.log.error(r), r;
|
|
616
676
|
}
|
|
617
677
|
}
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
678
|
+
/**
|
|
679
|
+
* Called in top-level error handler or by child component on unhandled error.
|
|
680
|
+
* Replace shadow root with either <slot> or template[data-component-fallback]
|
|
681
|
+
* slot on failure
|
|
682
|
+
*
|
|
683
|
+
* @param e
|
|
684
|
+
*/
|
|
621
685
|
unmount(t) {
|
|
622
686
|
var n;
|
|
687
|
+
this.log.debug("unmount", { error: t });
|
|
623
688
|
const e = this.querySelector(
|
|
624
689
|
"template[data-component-fallback]"
|
|
625
690
|
) ?? this.querySelector("template");
|
|
626
|
-
e && ((n = this.shadowRoot) == null || n.replaceChildren(e.content.cloneNode(!0))), this.dataset.cccError || (this.dataset.cccError = W(t.name.replace("CCC", ""))), delete this.dataset.cccReady, this.observer.disconnect();
|
|
691
|
+
e && (this.log.debug("unmount replacing shadowRoot with fallback"), (n = this.shadowRoot) == null || n.replaceChildren(e.content.cloneNode(!0))), this.dataset.cccError || (this.dataset.cccError = W(t.name.replace("CCC", ""))), delete this.dataset.cccReady, this.observer.disconnect();
|
|
627
692
|
}
|
|
693
|
+
/**
|
|
694
|
+
* Asynchronously loads the CCC child component.
|
|
695
|
+
*
|
|
696
|
+
* @returns Promise resolving to component renderer function
|
|
697
|
+
*/
|
|
628
698
|
async load() {
|
|
629
699
|
var c;
|
|
630
|
-
if (!this.component.isValid)
|
|
700
|
+
if (this.log.debug("load"), !this.component.isValid)
|
|
631
701
|
throw new Error("No path found");
|
|
632
702
|
const t = this.getAttribute("path"), e = this.getAttribute("version"), n = Number(this.getAttribute("load-timeout") || 1e4), r = this.getAttribute("test-env");
|
|
633
|
-
this.testUrl =
|
|
703
|
+
this.testUrl = X(r);
|
|
634
704
|
const s = await Q(
|
|
635
705
|
this.component.name,
|
|
636
706
|
this.testUrl
|
|
637
707
|
), i = this.getAttribute("id");
|
|
638
|
-
s && this.testUrl && this.injectViteScripts(), this.source = s ? `${(c = this.testUrl) == null ? void 0 : c.origin}/src/${this.component.name}/index.jsx?id=${i}` : `https://www.ft.com/__component/${this.component.org}/${this.component.repo}${e ? `@${e}` : "@latest"}/${this.component.name}/${this.component.name}.js?id=${i}`;
|
|
708
|
+
s && this.testUrl && (this.log.debug("load adding Vite scripts"), this.injectViteScripts()), this.source = s ? `${(c = this.testUrl) == null ? void 0 : c.origin}/src/${this.component.name}/index.jsx?id=${i}` : `https://www.ft.com/__component/${this.component.org}/${this.component.repo}${e ? `@${e}` : "@latest"}/${this.component.name}/${this.component.name}.js?id=${i}`;
|
|
639
709
|
try {
|
|
640
710
|
return await new Promise(
|
|
641
711
|
(a, h) => {
|
|
642
|
-
const
|
|
712
|
+
const l = setTimeout(() => {
|
|
643
713
|
this.log.error("CCC import timeout error"), h(
|
|
644
714
|
new J({
|
|
645
715
|
component: this.component,
|
|
@@ -654,7 +724,7 @@ class tt extends HTMLElement {
|
|
|
654
724
|
/* @vite-ignore */
|
|
655
725
|
).then(({ default: u }) => {
|
|
656
726
|
if (u)
|
|
657
|
-
clearTimeout(
|
|
727
|
+
clearTimeout(l), a(u);
|
|
658
728
|
else
|
|
659
729
|
throw new w(
|
|
660
730
|
"No component renderer default export found",
|
|
@@ -664,7 +734,7 @@ class tt extends HTMLElement {
|
|
|
664
734
|
}
|
|
665
735
|
);
|
|
666
736
|
}).catch((u) => {
|
|
667
|
-
clearTimeout(
|
|
737
|
+
clearTimeout(l), this.log.error(u), u instanceof Error && !(u instanceof w) ? h(
|
|
668
738
|
new w(u.message, {
|
|
669
739
|
component: this.component,
|
|
670
740
|
source: this.source
|
|
@@ -672,7 +742,7 @@ class tt extends HTMLElement {
|
|
|
672
742
|
) : h(u);
|
|
673
743
|
});
|
|
674
744
|
else
|
|
675
|
-
throw clearTimeout(
|
|
745
|
+
throw clearTimeout(l), new w(`Unable to mount ${t}`, {
|
|
676
746
|
component: this.component,
|
|
677
747
|
source: this.source
|
|
678
748
|
});
|
|
@@ -684,8 +754,26 @@ class tt extends HTMLElement {
|
|
|
684
754
|
), a;
|
|
685
755
|
}
|
|
686
756
|
}
|
|
757
|
+
/**
|
|
758
|
+
* Called whenever the <custom-code-component>'s attributes are changed.
|
|
759
|
+
* Currently only used to dynamically set log level.
|
|
760
|
+
*
|
|
761
|
+
* @param name
|
|
762
|
+
* @param oldValue
|
|
763
|
+
* @param newValue
|
|
764
|
+
*/
|
|
765
|
+
attributeChangedCallback(t, e, n) {
|
|
766
|
+
switch (this.log.debug("attributeChangedCallback lifecycle method", {
|
|
767
|
+
name: t,
|
|
768
|
+
oldValue: e,
|
|
769
|
+
newValue: n
|
|
770
|
+
}), t) {
|
|
771
|
+
case "log":
|
|
772
|
+
this.log.setLogLevel(n);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
687
775
|
}
|
|
688
776
|
export {
|
|
689
|
-
|
|
777
|
+
et as FTCustomCodeComponent
|
|
690
778
|
};
|
|
691
779
|
//# sourceMappingURL=custom-element.js.map
|