@financial-times/custom-code-component 2.0.1-alpha.10 → 2.0.1-alpha.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.
@@ -1,7 +1,7 @@
1
- function l(o) {
2
- this.listenerMap = [{}, {}], o && this.root(o), this.handle = l.prototype.handle.bind(this), this._removedListeners = [];
1
+ function m(o) {
2
+ this.listenerMap = [{}, {}], o && this.root(o), this.handle = m.prototype.handle.bind(this), this._removedListeners = [];
3
3
  }
4
- l.prototype.root = function(o) {
4
+ m.prototype.root = function(o) {
5
5
  const t = this.listenerMap;
6
6
  let e;
7
7
  if (this.rootElement) {
@@ -19,24 +19,24 @@ 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
- l.prototype.captureForType = function(o) {
22
+ m.prototype.captureForType = function(o) {
23
23
  return ["blur", "error", "focus", "load", "resize", "scroll"].indexOf(o) !== -1;
24
24
  };
25
- l.prototype.on = function(o, t, e, n) {
26
- let s, r, i, c;
25
+ m.prototype.on = function(o, t, e, n) {
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 s = this.rootElement, r = this.listenerMap[n ? 1 : 0], r[o] || (s && s.addEventListener(o, this.handle, n), r[o] = []), t ? /^[a-z]+$/i.test(t) ? (c = t, i = T) : /^#[a-z0-9\-_]+$/i.test(t) ? (c = t.slice(1), i = S) : (c = t, i = Element.prototype.matches) : (c = null, i = $.bind(this)), r[o].push({
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 = T) : /^#[a-z0-9\-_]+$/i.test(t) ? (c = t.slice(1), i = $) : (c = t, i = Element.prototype.matches) : (c = null, i = S.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
- l.prototype.off = function(o, t, e, n) {
39
- let s, r, i, c, h;
38
+ m.prototype.off = function(o, t, e, n) {
39
+ let r, s, i, c, h;
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;
42
42
  if (i = this.listenerMap[n ? 1 : 0], !o) {
@@ -46,18 +46,18 @@ l.prototype.off = function(o, t, e, n) {
46
46
  }
47
47
  if (c = i[o], !c || !c.length)
48
48
  return this;
49
- for (s = c.length - 1; s >= 0; s--)
50
- r = c[s], (!t || t === r.selector) && (!e || e === r.handler) && (this._removedListeners.push(r), c.splice(s, 1));
49
+ for (r = c.length - 1; r >= 0; r--)
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
- l.prototype.handle = function(o) {
53
+ m.prototype.handle = function(o) {
54
54
  let t, e;
55
55
  const n = o.type;
56
- let s, r, i, c, h = [], a;
57
- const m = "ftLabsDelegateIgnore";
58
- if (o[m] === !0)
56
+ let r, s, i, c, h = [], a;
57
+ const d = "ftLabsDelegateIgnore";
58
+ if (o[d] === !0)
59
59
  return;
60
- switch (a = o.target, a.nodeType === 3 && (a = a.parentNode), a.correspondingUseElement && (a = a.correspondingUseElement), s = this.rootElement, r = o.eventPhase || (o.target !== o.currentTarget ? 3 : 2), r) {
60
+ switch (a = o.target, a.nodeType === 3 && (a = a.parentNode), a.correspondingUseElement && (a = a.correspondingUseElement), r = this.rootElement, s = o.eventPhase || (o.target !== o.currentTarget ? 3 : 2), s) {
61
61
  case 1:
62
62
  h = this.listenerMap[1][n];
63
63
  break;
@@ -72,24 +72,24 @@ l.prototype.handle = function(o) {
72
72
  for (e = h.length; a && e; ) {
73
73
  for (t = 0; t < e && (i = h[t], !!i); t++)
74
74
  a.tagName && ["button", "input", "select", "textarea"].indexOf(a.tagName.toLowerCase()) > -1 && a.hasAttribute("disabled") ? u = [] : i.matcher.call(a, i.matcherParam, a) && u.push([o, a, i]);
75
- if (a === s || (e = h.length, a = a.parentElement || a.parentNode, a instanceof HTMLDocument))
75
+ if (a === r || (e = h.length, a = a.parentElement || a.parentNode, a instanceof HTMLDocument))
76
76
  break;
77
77
  }
78
- let b;
78
+ let E;
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][m] = !0, u[t][0].preventDefault(), b = !1;
81
+ u[t][0][d] = !0, u[t][0].preventDefault(), E = !1;
82
82
  break;
83
83
  }
84
- return b;
84
+ return E;
85
85
  };
86
- l.prototype.fire = function(o, t, e) {
86
+ m.prototype.fire = function(o, t, e) {
87
87
  return e.handler.call(t, o, t);
88
88
  };
89
89
  function T(o, t) {
90
90
  return o.toLowerCase() === t.tagName.toLowerCase();
91
91
  }
92
- function $(o, t) {
92
+ function S(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,10 +97,10 @@ function $(o, t) {
97
97
  t === window
98
98
  ) : this.rootElement === t;
99
99
  }
100
- function S(o, t) {
100
+ function $(o, t) {
101
101
  return o === t.id;
102
102
  }
103
- l.prototype.destroy = function() {
103
+ m.prototype.destroy = function() {
104
104
  this.off(), this.root();
105
105
  };
106
106
  function y(o) {
@@ -142,11 +142,11 @@ class C {
142
142
  }
143
143
  }
144
144
  const L = (o, t, e) => {
145
- const n = Array.from((o == null ? void 0 : o.querySelectorAll(e)) ?? []), s = n.findIndex((r) => r === t);
146
- if (s !== -1)
145
+ const n = Array.from((o == null ? void 0 : o.querySelectorAll(e)) ?? []), r = n.findIndex((s) => s === t);
146
+ if (r !== -1)
147
147
  return {
148
148
  siblings: n.length,
149
- position: s
149
+ position: r
150
150
  };
151
151
  }, k = [
152
152
  "nodeName",
@@ -178,25 +178,25 @@ const L = (o, t, e) => {
178
178
  t[e.name] = e.value;
179
179
  }), t), M = (o, t, e) => {
180
180
  const n = {};
181
- return e && k.forEach((s) => {
182
- typeof t[s] < "u" && s !== "id" && (n[s] = t[s]);
183
- }), o.filter((s) => s.name.match(/^data-trackable-context-/i)).forEach((s) => {
184
- n[s.name.replace("data-trackable-context-", "")] = x(s.value);
181
+ return e && k.forEach((r) => {
182
+ typeof t[r] < "u" && r !== "id" && (n[r] = t[r]);
183
+ }), o.filter((r) => r.name.match(/^data-trackable-context-/i)).forEach((r) => {
184
+ n[r.name.replace("data-trackable-context-", "")] = x(r.value);
185
185
  }), n;
186
186
  };
187
187
  function D(o, t) {
188
- const e = o, n = e != null && e.getAttribute("data-trackable") ? `[data-trackable="${e.getAttribute("data-trackable")}"]` : e == null ? void 0 : e.nodeName, s = [], r = {};
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
190
  const i = O(o), c = Array.from(o.attributes);
191
191
  let h = I(c, i);
192
192
  h["data-trackable"] && (h = Object.assign(
193
193
  h,
194
194
  L(o, e, n)
195
- )), s.push(h);
195
+ )), r.push(h);
196
196
  const a = M(c, i, o === e);
197
- v(a, r), o = o.parentNode;
197
+ v(a, s), o = o.parentNode;
198
198
  }
199
- return { trace: s, customContext: r };
199
+ return { trace: r, customContext: s };
200
200
  }
201
201
  const U = ["ctrlKey", "altKey", "shiftKey", "metaKey"];
202
202
  class F {
@@ -204,13 +204,13 @@ class F {
204
204
  id: t = "00000000-0000-0000-0000-000000000000",
205
205
  name: e = "ccc-component",
206
206
  subtype: n = "interactive",
207
- teamName: s = "djd",
208
- shadowRoot: r = null,
207
+ teamName: r = "djd",
208
+ shadowRoot: s = null,
209
209
  category: i = "cta",
210
210
  elements: c = 'a, button, input, [role="button"]',
211
211
  logger: h
212
212
  }) {
213
- this.cccId = t, this.cccName = e, this.subtype = n, this.teamName = s, this.shadowRoot = r, this.category = i, this.elements = c, this.isInitialised = !1, this.log = h ?? new C();
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 = h ?? new C();
214
214
  }
215
215
  // Get properties for the event (as opposed to properties of the clicked element)
216
216
  getEventProperties(t) {
@@ -219,21 +219,21 @@ class F {
219
219
  if (t[n])
220
220
  try {
221
221
  e[n] = y(t[n]);
222
- } catch (s) {
223
- this.log.info(s);
222
+ } catch (r) {
223
+ this.log.info(r);
224
224
  }
225
225
  return e;
226
226
  }
227
227
  // Controller for handling click events
228
228
  handleClickEvent(t, e) {
229
- return (n, s) => {
230
- const r = this.getEventProperties(n), { trace: i, customContext: c } = D(s, e);
231
- r.custom = s.dataset && s.dataset.custom ? JSON.parse(s.dataset.custom) : null, r.domPathTokens = i, r.component = {
229
+ return (n, r) => {
230
+ const s = this.getEventProperties(n), { trace: i, customContext: c } = D(r, e);
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
- }, r.teamName = this.teamName, r.url = document.URL, v(c, r), r.method = "ftCustomAnalytics", t = { ...t, ...r }, document.body.dispatchEvent(
236
+ }, s.teamName = this.teamName, s.url = document.URL, v(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,
@@ -272,28 +272,28 @@ class F {
272
272
  const n = {
273
273
  action: "click",
274
274
  category: this.category
275
- }, s = (e = this.shadowRoot) == null ? void 0 : e.querySelector("[data-component-root]");
276
- s && new l(s).on(
275
+ }, r = (e = this.shadowRoot) == null ? void 0 : e.querySelector("[data-component-root]");
276
+ r && new m(r).on(
277
277
  "click",
278
278
  this.elements,
279
- this.handleClickEvent(n, s),
279
+ this.handleClickEvent(n, r),
280
280
  !0
281
281
  );
282
282
  }
283
283
  }
284
284
  }
285
- class f {
285
+ class l {
286
286
  constructor(t) {
287
- const { org: e, repo: n, component: s, versionRange: r } = w(
287
+ const { org: e, repo: n, component: r, versionRange: s } = w(
288
288
  t
289
- ) ? t : f.fromString(t);
290
- this.org = e, this.repo = n, this.component = s, this.versionRange = r;
289
+ ) ? t : l.fromString(t);
290
+ this.org = e, this.repo = n, this.component = r, this.versionRange = s;
291
291
  }
292
292
  set path(t) {
293
- const { org: e, repo: n, component: s, versionRange: r } = w(
293
+ const { org: e, repo: n, component: r, versionRange: s } = w(
294
294
  t
295
- ) ? t : f.fromString(t);
296
- this.org = e, this.repo = n, this.component = s, this.versionRange = r;
295
+ ) ? t : l.fromString(t);
296
+ this.org = e, this.repo = n, this.component = r, this.versionRange = s;
297
297
  }
298
298
  get path() {
299
299
  return `${this.org}/${this.repo}@${this.versionRange}/${this.component}`;
@@ -304,37 +304,37 @@ class f {
304
304
  static fromString(t, e) {
305
305
  var c;
306
306
  if (!t)
307
- throw new d("No path specified");
307
+ throw new f("No path specified");
308
308
  const n = e ?? ((c = t.match(/@[^\/]+/)) == null ? void 0 : c.toString().replace("@", "")) ?? "unknown";
309
309
  if (!n)
310
- throw new d("No version specified");
311
- const [s, r, i] = t.replace(/@[^\/]+/, "").split("/").reverse();
312
- return new f({ org: i, repo: r, component: s, versionRange: n });
310
+ throw new f("No version specified");
311
+ const [r, s, i] = t.replace(/@[^\/]+/, "").split("/").reverse();
312
+ return new l({ org: i, repo: s, component: r, versionRange: n });
313
313
  }
314
314
  }
315
315
  function w(o) {
316
316
  return typeof o == "object" && o !== null ? "org" in o && "repo" in o && "component" in o : !1;
317
317
  }
318
- class d extends Error {
318
+ class f extends Error {
319
319
  constructor(t, e) {
320
- var n = (...s) => {
321
- super(...s);
320
+ var n = (...r) => {
321
+ super(...r);
322
322
  };
323
323
  !e && t ? (n(t), this.component = null) : typeof (e == null ? void 0 : e.component) == "string" ? (n(
324
324
  t ?? `${e.cause ?? "Unknown error"} in ${e.component} imported from ${e.source ?? "an undefined source"}.`
325
- ), this.component = f.fromString(e.component)) : w(e == null ? void 0 : e.component) ? (n(
325
+ ), this.component = l.fromString(e.component)) : w(e == null ? void 0 : e.component) ? (n(
326
326
  t ?? `${e.cause ?? "Unknown error"} in ${e.component.org}/${e.component.repo}/${e.component.component}@${e.component.versionRange} imported from ${e.source ?? "an undefined source"}.`
327
- ), this.component = new f(e.component)) : (n(
327
+ ), this.component = new l(e.component)) : (n(
328
328
  `${(e == null ? void 0 : e.cause) ?? "Unknown error"} in unknown component imported from ${(e == null ? void 0 : e.source) ?? "unknown source"}.`
329
- ), this.component = null), this.source = e == null ? void 0 : e.source, Error.captureStackTrace && Error.captureStackTrace(this, d), this.name = "CCCError";
329
+ ), this.component = null), this.source = e == null ? void 0 : e.source, Error.captureStackTrace && Error.captureStackTrace(this, f), this.name = "CCCError";
330
330
  }
331
331
  }
332
- class g extends d {
332
+ class g extends f {
333
333
  constructor(t, e) {
334
334
  super(t, { ...e, cause: "Import error" }), this.name = "CCCImportError";
335
335
  }
336
336
  }
337
- class W extends d {
337
+ class W extends f {
338
338
  constructor(t) {
339
339
  super(null, { ...t, cause: "Timeout error" }), this.name = "CCCTimeoutError";
340
340
  }
@@ -356,36 +356,36 @@ const _ = (o) => o.replace(
356
356
  (t, e) => (e ? "-" : "") + t.toLowerCase()
357
357
  );
358
358
  function V(o) {
359
- return E([
359
+ return b([
360
360
  "localhost",
361
361
  "local.ft.com",
362
362
  /^.*\.apps\.in\.ft\.com$/
363
363
  ], o);
364
364
  }
365
365
  function z() {
366
- return E([
366
+ return b([
367
367
  "localhost",
368
368
  "local.ft.com",
369
369
  /^.*\.in\.ft\.com$/
370
370
  ], window.location.hostname);
371
371
  }
372
372
  function J() {
373
- return E([
373
+ return b([
374
374
  "spark.ft.com",
375
375
  "spark-staging.ft.com"
376
376
  ], window.location.host);
377
377
  }
378
- function E(o, t) {
378
+ function b(o, t) {
379
379
  return t ? o.some((e) => typeof e == "string" ? e === t : e.test(t)) : !1;
380
380
  }
381
381
  function H(o) {
382
- if (o === null)
382
+ if (!o)
383
383
  return;
384
384
  let t;
385
385
  const e = new URL("http://localhost:5173");
386
386
  try {
387
387
  if (typeof o == "string") {
388
- if ((o === "" || o.toLowerCase() === "true") && z())
388
+ if (o === "true" && z())
389
389
  t = e;
390
390
  else if (t = o.startsWith("http://") || o.startsWith("https://") ? new URL(o) : void 0, t && !V(t == null ? void 0 : t.hostname))
391
391
  throw new Error("Unsafe testing host override");
@@ -401,16 +401,16 @@ async function K(o) {
401
401
  return !1;
402
402
  function t(n) {
403
403
  try {
404
- return new Promise((s) => {
405
- const r = new WebSocket(`ws://${n}`, "vite-hmr"), i = setTimeout(() => {
406
- s(r.readyState === WebSocket.OPEN), r.close();
404
+ return new Promise((r) => {
405
+ const s = new WebSocket(`ws://${n}`, "vite-hmr"), i = setTimeout(() => {
406
+ r(s.readyState === WebSocket.OPEN), s.close();
407
407
  }, 50);
408
- r.addEventListener("error", () => {
409
- clearTimeout(i), r.close(), s(!1);
408
+ s.addEventListener("error", () => {
409
+ clearTimeout(i), s.close(), r(!1);
410
410
  }, { once: !0 });
411
411
  });
412
- } catch {
413
- return Promise.resolve(!1);
412
+ } catch (r) {
413
+ return console.error("WebSocket creation failed:", r), Promise.resolve(!1);
414
414
  }
415
415
  }
416
416
  return await t(o == null ? void 0 : o.host);
@@ -427,29 +427,30 @@ class q extends HTMLElement {
427
427
  "env",
428
428
  "load-timeout"
429
429
  ]), this.channel = new MessageChannel(), this.initTracking = async () => {
430
- var e;
430
+ var r;
431
431
  try {
432
- (e = this.tracking) == null || e.init(this.id);
433
- } catch (n) {
434
- const s = this.getAttribute("path"), r = this.getAttribute("version");
432
+ (r = this.tracking) == null || r.init(this.id);
433
+ } catch (s) {
434
+ const i = this.getAttribute("path"), c = this.getAttribute("version");
435
435
  this.log.info(
436
- `Error initialising tracking on <custom-code-component> ${s}@${r}`
437
- ), this.log.error(n);
436
+ `Error initialising tracking on <custom-code-component> ${i}@${c}`
437
+ ), this.log.error(s);
438
438
  }
439
439
  }, this.log = new C({
440
440
  level: N(this.getAttribute("log"))
441
441
  });
442
- const t = HTMLElement.prototype.hasOwnProperty("attachInternals");
442
+ const t = this.getAttribute("path"), e = this.getAttribute("version");
443
+ this.component = l.fromString(t, e), this.lightRoot = Array.from(this.childNodes);
444
+ const n = HTMLElement.prototype.hasOwnProperty("attachInternals");
443
445
  try {
444
- const e = t && this.attachInternals();
445
- } catch (e) {
446
- this.log.error(e);
446
+ const r = n && this.attachInternals();
447
+ } catch (r) {
448
+ this.log.error(r);
447
449
  }
448
450
  }
449
451
  async connectedCallback() {
450
452
  try {
451
- const t = this.getAttribute("path"), e = this.getAttribute("version");
452
- this.component = f.fromString(t, e), this.lightRoot = Array.from(this.childNodes), this.app = await this.load(), await this.mount(), await this.initTracking();
453
+ this.app = await this.load(), await this.mount(), await this.initTracking();
453
454
  } catch (t) {
454
455
  t instanceof Error && requestAnimationFrame(() => {
455
456
  this.emitError(t);
@@ -459,7 +460,7 @@ class q extends HTMLElement {
459
460
  emitError(t) {
460
461
  var n;
461
462
  let e;
462
- if (t instanceof d && ((n = t.name) != null && n.startsWith("CCC")) ? e = t.name.replace(/^CCC/, "ccc:") : e = `ccc:${(t == null ? void 0 : t.name) ?? "UnknownError"}`, !e)
463
+ if (t instanceof f && ((n = t.name) != null && n.startsWith("CCC")) ? e = t.name.replace(/^CCC/, "ccc:") : e = `ccc:${(t == null ? void 0 : t.name) ?? "UnknownError"}`, !e)
463
464
  return this.log.debug(t);
464
465
  this.dispatchEvent(
465
466
  new ErrorEvent(e, {
@@ -490,61 +491,56 @@ class q extends HTMLElement {
490
491
  this.channel.port1.postMessage(t);
491
492
  }
492
493
  async mount(t) {
493
- var e, n;
494
494
  try {
495
- if (this.mode = this.getAttribute("shadow-open") == "false" ? "closed" : "open", this.component) {
496
- if (this.dispatchEvent(
497
- new j({
498
- component: this.component,
499
- source: this.source
500
- })
501
- ), this.dataset.cccReady = "true", delete this.dataset.cccError, !this.app)
502
- throw new Error("CCC mounted without App");
503
- const s = this.shadowRoot !== null, r = this.shadowRoot ?? this.attachShadow({ mode: this.mode }), i = JSON.parse(this.getAttribute("data-component-props")), c = Object.fromEntries(
504
- [...this.attributes].filter((u) => !this.RESERVED_ATTRS.has(u.name)).map((u) => [u.name, u.value])
505
- );
506
- this.tracking = new F({
507
- name: (e = this.component) == null ? void 0 : e.toString(),
508
- subtype: "interactive",
509
- teamName: "djd",
510
- shadowRoot: this.shadowRoot,
511
- logger: this.log
512
- });
513
- const { unmount: h, onmessage: a, ready: m } = this.app(
514
- r,
515
- {
516
- ...c,
517
- data: i,
518
- port: this.channel.port2,
519
- tracking: this.tracking,
520
- prerendered: !!t,
521
- children: this.children
522
- },
523
- s
524
- ) || {};
525
- h && (this.onunmount = h), a && (this.onmessage = a), m && this.onready(m);
526
- }
527
- } catch (s) {
495
+ if (this.mode = this.getAttribute("shadow-open") == "false" ? "closed" : "open", this.dispatchEvent(
496
+ new j({
497
+ component: this.component,
498
+ source: this.source
499
+ })
500
+ ), this.dataset.cccReady = "true", delete this.dataset.cccError, !this.app)
501
+ throw new Error("CCC mounted without App");
502
+ const e = this.shadowRoot !== null, n = this.shadowRoot ?? this.attachShadow({ mode: this.mode }), r = JSON.parse(this.getAttribute("data-component-props")), s = Object.fromEntries(
503
+ [...this.attributes].filter((a) => !this.RESERVED_ATTRS.has(a.name)).map((a) => [a.name, a.value])
504
+ );
505
+ this.tracking = new F({
506
+ name: this.component.toString(),
507
+ subtype: "interactive",
508
+ teamName: "djd",
509
+ shadowRoot: this.shadowRoot,
510
+ logger: this.log
511
+ });
512
+ const { unmount: i, onmessage: c, ready: h } = this.app(
513
+ n,
514
+ {
515
+ ...s,
516
+ data: r,
517
+ port: this.channel.port2,
518
+ tracking: this.tracking,
519
+ prerendered: !!t,
520
+ children: this.children
521
+ },
522
+ e
523
+ ) || {};
524
+ i && (this.onunmount = i), c && (this.onmessage = c), h && this.onready(h);
525
+ } catch (e) {
528
526
  throw this.log.info(
529
- `<custom-code-component> uncaught error during mount from ${(n = this.component) == null ? void 0 : n.toString()}`
530
- ), this.log.error(s), s;
527
+ `<custom-code-component> uncaught error during mount from ${this.component.toString()}`
528
+ ), this.log.error(e), e;
531
529
  }
532
530
  }
533
531
  // Called in top-level error handler
534
532
  // Replace shadow root with light DOM children on error
535
533
  unmount(t) {
536
534
  var e;
537
- this.lightRoot && (this.onunmount(), (e = this.shadowRoot) == null || e.replaceChildren(...this.lightRoot), this.dataset.cccError || (this.dataset.cccError = _(t.name.replace("CCC", ""))), delete this.dataset.cccReady);
535
+ this.onunmount(), (e = this.shadowRoot) == null || e.replaceChildren(...this.lightRoot), this.dataset.cccError || (this.dataset.cccError = _(t.name.replace("CCC", ""))), delete this.dataset.cccReady;
538
536
  }
539
537
  async load() {
540
- if (!this.component)
541
- throw new Error("No path found");
542
- const t = this.getAttribute("path"), e = this.getAttribute("version"), n = Number(this.getAttribute("load-timeout") || 1e4), s = this.getAttribute("testEnv"), r = H(s), i = await K(r), c = this.getAttribute("id");
543
- this.source = i ? `${r == null ? void 0 : r.origin}/src/${this.component.component}/index.jsx?id=${c}` : `https://www.ft.com/__component/${this.component.org}/${this.component.repo}${e ? `@${e}` : "@latest"}/${this.component.component}/${this.component.component}.js?id=${c}`;
538
+ const t = this.getAttribute("path"), e = this.getAttribute("version"), n = Number(this.getAttribute("load-timeout") || 1e4), r = this.getAttribute("testEnv"), s = H(r), i = await K(s), c = this.getAttribute("id");
539
+ this.source = i ? `${s == null ? void 0 : s.origin}/src/${this.component.component}/index.jsx?id=${c}` : `https://www.ft.com/__component/${this.component.org}/${this.component.repo}${e ? `@${e}` : "@latest"}/${this.component.component}/${this.component.component}.js?id=${c}`;
544
540
  try {
545
541
  return await new Promise(
546
542
  (h, a) => {
547
- const m = setTimeout(() => {
543
+ const d = setTimeout(() => {
548
544
  this.log.error("CCC import timeout error"), a(
549
545
  new W({
550
546
  component: this.component,
@@ -559,7 +555,7 @@ class q extends HTMLElement {
559
555
  /* @vite-ignore */
560
556
  ).then(({ default: u }) => {
561
557
  if (u)
562
- clearTimeout(m), h(u);
558
+ clearTimeout(d), h(u);
563
559
  else
564
560
  throw new g(
565
561
  "No component renderer default export found",
@@ -569,7 +565,7 @@ class q extends HTMLElement {
569
565
  }
570
566
  );
571
567
  }).catch((u) => {
572
- clearTimeout(m), this.log.error(u), u instanceof Error && !(u instanceof g) ? a(
568
+ clearTimeout(d), this.log.error(u), u instanceof Error && !(u instanceof g) ? a(
573
569
  new g(u.message, {
574
570
  component: this.component,
575
571
  source: this.source
@@ -577,7 +573,7 @@ class q extends HTMLElement {
577
573
  ) : a(u);
578
574
  });
579
575
  else
580
- throw clearTimeout(m), new g(`Unable to mount ${t}`, {
576
+ throw clearTimeout(d), new g(`Unable to mount ${t}`, {
581
577
  component: this.component,
582
578
  source: this.source
583
579
  });
@@ -590,9 +586,6 @@ class q extends HTMLElement {
590
586
  }
591
587
  }
592
588
  }
593
- const B = () => customElements.define("custom-code-component", q);
594
- customElements && !customElements.get("custom-code-component") && B();
595
589
  export {
596
- B as init
590
+ q as FTCustomCodeComponent
597
591
  };
598
- //# sourceMappingURL=index.js.map
@@ -13,8 +13,8 @@ export declare class FTCustomCodeComponent extends HTMLElement {
13
13
  RESERVED_ATTRS: Set<string>;
14
14
  source?: string;
15
15
  tracking?: Tracking;
16
- lightRoot?: ChildNode[];
17
- component?: ComponentPath;
16
+ lightRoot: ChildNode[];
17
+ component: ComponentPath;
18
18
  log: Logger;
19
19
  constructor();
20
20
  connectedCallback(): Promise<void>;
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@financial-times/custom-code-component",
3
- "version": "2.0.1-alpha.10",
3
+ "version": "2.0.1-alpha.5",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
7
- "default": "./dist/index.js",
8
- "types": "./dist/webcomponent/src/index.d.ts"
7
+ "import": "./dist/custom-code-component.js",
8
+ "types": "./dist/custom-code-component.d.ts"
9
9
  }
10
10
  },
11
11
  "scripts": {
@@ -34,17 +34,25 @@ export class FTCustomCodeComponent extends HTMLElement {
34
34
 
35
35
  source?: string;
36
36
  tracking?: Tracking;
37
- lightRoot?: ChildNode[];
38
- component?: ComponentPath;
37
+ lightRoot: ChildNode[];
38
+ component: ComponentPath;
39
39
 
40
40
  log: Logger;
41
41
 
42
42
  constructor() {
43
43
  super();
44
+
44
45
  this.log = new Logger({
45
46
  level: convertStringLogLevel(this.getAttribute("log")),
46
47
  });
47
48
 
49
+ const path = this.getAttribute("path");
50
+ const versionRange = this.getAttribute("version");
51
+ this.component = ComponentPath.fromString(path, versionRange);
52
+
53
+ // Backup the light root to restore in case of error
54
+ this.lightRoot = Array.from(this.childNodes);
55
+
48
56
  const supportsDeclarative =
49
57
  HTMLElement.prototype.hasOwnProperty("attachInternals");
50
58
 
@@ -57,12 +65,6 @@ export class FTCustomCodeComponent extends HTMLElement {
57
65
 
58
66
  async connectedCallback() {
59
67
  try {
60
- const path = this.getAttribute("path");
61
- const versionRange = this.getAttribute("version");
62
- this.component = ComponentPath.fromString(path, versionRange);
63
-
64
- // Backup the light root to restore in case of error
65
- this.lightRoot = Array.from(this.childNodes);
66
68
  this.app = await this.load();
67
69
  await this.mount();
68
70
  await this.initTracking();
@@ -127,64 +129,61 @@ export class FTCustomCodeComponent extends HTMLElement {
127
129
  try {
128
130
  this.mode =
129
131
  this.getAttribute("shadow-open") == "false" ? "closed" : "open";
130
- if (this.component) {
131
-
132
- this.dispatchEvent(
133
- new CCCConnectedEvent({
134
- component: this.component,
135
- source: this.source,
136
- })
137
- );
138
132
 
139
- this.dataset.cccReady = "true";
140
- delete this.dataset.cccError;
141
-
133
+ this.dispatchEvent(
134
+ new CCCConnectedEvent({
135
+ component: this.component,
136
+ source: this.source,
137
+ })
138
+ );
142
139
 
143
- if (!this.app) {
144
- throw new Error("CCC mounted without App");
145
- }
140
+ this.dataset.cccReady = "true";
141
+ delete this.dataset.cccError;
146
142
 
147
- const ssr = this.shadowRoot !== null;
148
- const shadow = this.shadowRoot ?? this.attachShadow({ mode: this.mode });
143
+ if (!this.app) {
144
+ throw new Error("CCC mounted without App");
145
+ }
149
146
 
150
- const data = JSON.parse(this.getAttribute("data-component-props")!);
147
+ const ssr = this.shadowRoot !== null;
148
+ const shadow = this.shadowRoot ?? this.attachShadow({ mode: this.mode });
151
149
 
152
- const extraProps = Object.fromEntries(
153
- [...this.attributes]
154
- .filter((attribute) => !this.RESERVED_ATTRS.has(attribute.name))
155
- .map((attribute) => [attribute.name, attribute.value])
156
- );
150
+ const data = JSON.parse(this.getAttribute("data-component-props")!);
157
151
 
158
- // Create tracking instance
159
- this.tracking = new Tracking({
160
- name: this.component?.toString(),
161
- subtype: "interactive",
162
- teamName: "djd",
163
- shadowRoot: this.shadowRoot,
164
- logger: this.log,
165
- });
152
+ const extraProps = Object.fromEntries(
153
+ [...this.attributes]
154
+ .filter((attribute) => !this.RESERVED_ATTRS.has(attribute.name))
155
+ .map((attribute) => [attribute.name, attribute.value])
156
+ );
166
157
 
167
- const { unmount, onmessage, ready } =
168
- this.app(
169
- shadow,
170
- {
171
- ...extraProps,
172
- data,
173
- port: this.channel.port2,
174
- tracking: this.tracking,
175
- prerendered: !!prerendered,
176
- children: this.children,
177
- },
178
- ssr
179
- ) || {};
180
-
181
- if (unmount) this.onunmount = unmount;
182
- if (onmessage) this.onmessage = onmessage;
183
- if (ready) this.onready(ready);
184
- }
158
+ // Create tracking instance
159
+ this.tracking = new Tracking({
160
+ name: this.component.toString(),
161
+ subtype: "interactive",
162
+ teamName: "djd",
163
+ shadowRoot: this.shadowRoot,
164
+ logger: this.log,
165
+ });
166
+
167
+ const { unmount, onmessage, ready } =
168
+ this.app(
169
+ shadow,
170
+ {
171
+ ...extraProps,
172
+ data,
173
+ port: this.channel.port2,
174
+ tracking: this.tracking,
175
+ prerendered: !!prerendered,
176
+ children: this.children,
177
+ },
178
+ ssr
179
+ ) || {};
180
+
181
+ if (unmount) this.onunmount = unmount;
182
+ if (onmessage) this.onmessage = onmessage;
183
+ if (ready) this.onready(ready);
185
184
  } catch (err) {
186
185
  this.log.info(
187
- `<custom-code-component> uncaught error during mount from ${this.component?.toString()}`
186
+ `<custom-code-component> uncaught error during mount from ${this.component.toString()}`
188
187
  );
189
188
  this.log.error(err);
190
189
 
@@ -195,20 +194,15 @@ export class FTCustomCodeComponent extends HTMLElement {
195
194
  // Called in top-level error handler
196
195
  // Replace shadow root with light DOM children on error
197
196
  unmount(e: Error) {
198
- if (this.lightRoot) {
199
- this.onunmount();
200
- this.shadowRoot?.replaceChildren(...this.lightRoot);
201
-
202
- if (!this.dataset.cccError)
203
- this.dataset.cccError = kebabize(e.name.replace("CCC", ""));
204
- delete this.dataset.cccReady;
205
- }
197
+ this.onunmount();
198
+ this.shadowRoot?.replaceChildren(...this.lightRoot);
199
+
200
+ if (!this.dataset.cccError)
201
+ this.dataset.cccError = kebabize(e.name.replace("CCC", ""));
202
+ delete this.dataset.cccReady;
206
203
  }
207
204
 
208
205
  async load() {
209
- if (!this.component) {
210
- throw new Error("No path found")
211
- }
212
206
  const path = this.getAttribute("path");
213
207
  const componentVersionRange = this.getAttribute("version");
214
208
  const timeout = Number(this.getAttribute("load-timeout") || 10000);
@@ -231,7 +225,7 @@ export class FTCustomCodeComponent extends HTMLElement {
231
225
  this.log.error("CCC import timeout error");
232
226
  reject(
233
227
  new CCCTimeoutError({
234
- component: this.component!,
228
+ component: this.component,
235
229
  source: this.source,
236
230
  })
237
231
  );
@@ -247,7 +241,7 @@ export class FTCustomCodeComponent extends HTMLElement {
247
241
  throw new CCCImportError(
248
242
  "No component renderer default export found",
249
243
  {
250
- component: this.component!,
244
+ component: this.component,
251
245
  source: this.source,
252
246
  }
253
247
  );
@@ -258,7 +252,7 @@ export class FTCustomCodeComponent extends HTMLElement {
258
252
  if (e instanceof Error && !(e instanceof CCCImportError)) {
259
253
  reject(
260
254
  new CCCImportError(e.message, {
261
- component: this.component!,
255
+ component: this.component,
262
256
  source: this.source,
263
257
  })
264
258
  );
@@ -269,7 +263,7 @@ export class FTCustomCodeComponent extends HTMLElement {
269
263
  } else {
270
264
  clearTimeout(to);
271
265
  throw new CCCImportError(`Unable to mount ${path}`, {
272
- component: this.component!,
266
+ component: this.component,
273
267
  source: this.source,
274
268
  });
275
269
  }
@@ -8,16 +8,15 @@ import { isLocalEnv, isSafeTestEnv, isSparkEnv } from "./util"
8
8
  * @returns A `URL` object if valid and safe, or `undefined` if invalid.
9
9
  */
10
10
  export function assignTestURL(testEnv: string | null): URL | undefined {
11
- if (testEnv === null) {
11
+ if (!testEnv) {
12
12
  return
13
13
  }
14
-
15
14
  let testUrl
16
15
  const defaultTestUrl = new URL('http://localhost:5173')
17
16
 
18
17
  try {
19
18
  if (typeof testEnv === 'string') {
20
- if ((testEnv === '' || testEnv.toLowerCase() === 'true') && isLocalEnv()) {
19
+ if (testEnv === 'true' && isLocalEnv()) {
21
20
  testUrl = defaultTestUrl
22
21
  } else {
23
22
  const hasProtocol = testEnv.startsWith('http://') || testEnv.startsWith('https://')
@@ -67,6 +66,7 @@ export async function useComponentTestEnv(testUrl?: URL): Promise<boolean> {
67
66
  }, { once: true });
68
67
  });
69
68
  } catch (err) {
69
+ console.error("WebSocket creation failed:", err);
70
70
  return Promise.resolve(false);
71
71
  }
72
72
  }
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sources":["../node_modules/ftdomdelegate/main.js","../../node_modules/@financial-times/o-tracking/src/javascript/utils.js","../src/logger.ts","../src/get-trace.ts","../src/tracking.ts","../src/path.ts","../src/errors.ts","../src/events.ts","../src/util.ts","../src/environment.ts","../src/custom-code-component.ts","../src/index.ts"],"sourcesContent":["/**\n * DOM event delegator\n *\n * The delegator will listen\n * for events that bubble up\n * to the root node.\n *\n * @constructor\n * @param {Node|string} [root] The root node or a selector string matching the root node\n */\nfunction Delegate(root) {\n\n\t/**\n\t * Maintain a map of listener\n\t * lists, keyed by event name.\n\t *\n\t * @type Object\n\t */\n\tthis.listenerMap = [{}, {}];\n\tif (root) {\n\t\tthis.root(root);\n\t}\n\n\t/** @type function() */\n\tthis.handle = Delegate.prototype.handle.bind(this);\n\n\t// Cache of event listeners removed during an event cycle\n\tthis._removedListeners = [];\n}\n\n/**\n * Start listening for events\n * on the provided DOM element\n *\n * @param {Node|string} [root] The root node or a selector string matching the root node\n * @returns {Delegate} This method is chainable\n */\nDelegate.prototype.root = function (root) {\n\tconst listenerMap = this.listenerMap;\n\tlet eventType;\n\n\t// Remove master event listeners\n\tif (this.rootElement) {\n\t\tfor (eventType in listenerMap[1]) {\n\t\t\tif (listenerMap[1].hasOwnProperty(eventType)) {\n\t\t\t\tthis.rootElement.removeEventListener(eventType, this.handle, true);\n\t\t\t}\n\t\t}\n\t\tfor (eventType in listenerMap[0]) {\n\t\t\tif (listenerMap[0].hasOwnProperty(eventType)) {\n\t\t\t\tthis.rootElement.removeEventListener(eventType, this.handle, false);\n\t\t\t}\n\t\t}\n\t}\n\n\t// If no root or root is not\n\t// a dom node, then remove internal\n\t// root reference and exit here\n\tif (!root || !root.addEventListener) {\n\t\tif (this.rootElement) {\n\t\t\tdelete this.rootElement;\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * The root node at which\n\t * listeners are attached.\n\t *\n\t * @type Node\n\t */\n\tthis.rootElement = root;\n\n\t// Set up master event listeners\n\tfor (eventType in listenerMap[1]) {\n\t\tif (listenerMap[1].hasOwnProperty(eventType)) {\n\t\t\tthis.rootElement.addEventListener(eventType, this.handle, true);\n\t\t}\n\t}\n\tfor (eventType in listenerMap[0]) {\n\t\tif (listenerMap[0].hasOwnProperty(eventType)) {\n\t\t\tthis.rootElement.addEventListener(eventType, this.handle, false);\n\t\t}\n\t}\n\n\treturn this;\n};\n\n/**\n * @param {string} eventType\n * @returns boolean\n */\nDelegate.prototype.captureForType = function (eventType) {\n\treturn ['blur', 'error', 'focus', 'load', 'resize', 'scroll'].indexOf(eventType) !== -1;\n};\n\n/**\n * Attach a handler to one\n * event for all elements\n * that match the selector,\n * now or in the future\n *\n * The handler function receives\n * three arguments: the DOM event\n * object, the node that matched\n * the selector while the event\n * was bubbling and a reference\n * to itself. Within the handler,\n * 'this' is equal to the second\n * argument.\n *\n * The node that actually received\n * the event can be accessed via\n * 'event.target'.\n *\n * @param {string} eventType Listen for these events\n * @param {string|undefined} selector Only handle events on elements matching this selector, if undefined match root element\n * @param {function()} handler Handler function - event data passed here will be in event.data\n * @param {boolean} [useCapture] see 'useCapture' in <https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener>\n * @returns {Delegate} This method is chainable\n */\nDelegate.prototype.on = function (eventType, selector, handler, useCapture) {\n\tlet root;\n\tlet listenerMap;\n\tlet matcher;\n\tlet matcherParam;\n\n\tif (!eventType) {\n\t\tthrow new TypeError('Invalid event type: ' + eventType);\n\t}\n\n\t// handler can be passed as\n\t// the second or third argument\n\tif (typeof selector === 'function') {\n\t\tuseCapture = handler;\n\t\thandler = selector;\n\t\tselector = null;\n\t}\n\n\t// Fallback to sensible defaults\n\t// if useCapture not set\n\tif (useCapture === undefined) {\n\t\tuseCapture = this.captureForType(eventType);\n\t}\n\n\tif (typeof handler !== 'function') {\n\t\tthrow new TypeError('Handler must be a type of Function');\n\t}\n\n\troot = this.rootElement;\n\tlistenerMap = this.listenerMap[useCapture ? 1 : 0];\n\n\t// Add master handler for type if not created yet\n\tif (!listenerMap[eventType]) {\n\t\tif (root) {\n\t\t\troot.addEventListener(eventType, this.handle, useCapture);\n\t\t}\n\t\tlistenerMap[eventType] = [];\n\t}\n\n\tif (!selector) {\n\t\tmatcherParam = null;\n\n\t\t// COMPLEX - matchesRoot needs to have access to\n\t\t// this.rootElement, so bind the function to this.\n\t\tmatcher = matchesRoot.bind(this);\n\n\t\t// Compile a matcher for the given selector\n\t} else if (/^[a-z]+$/i.test(selector)) {\n\t\tmatcherParam = selector;\n\t\tmatcher = matchesTag;\n\t} else if (/^#[a-z0-9\\-_]+$/i.test(selector)) {\n\t\tmatcherParam = selector.slice(1);\n\t\tmatcher = matchesId;\n\t} else {\n\t\tmatcherParam = selector;\n\t\tmatcher = Element.prototype.matches;\n\t}\n\n\t// Add to the list of listeners\n\tlistenerMap[eventType].push({\n\t\tselector: selector,\n\t\thandler: handler,\n\t\tmatcher: matcher,\n\t\tmatcherParam: matcherParam\n\t});\n\n\treturn this;\n};\n\n/**\n * Remove an event handler\n * for elements that match\n * the selector, forever\n *\n * @param {string} [eventType] Remove handlers for events matching this type, considering the other parameters\n * @param {string} [selector] If this parameter is omitted, only handlers which match the other two will be removed\n * @param {function()} [handler] If this parameter is omitted, only handlers which match the previous two will be removed\n * @returns {Delegate} This method is chainable\n */\nDelegate.prototype.off = function (eventType, selector, handler, useCapture) {\n\tlet i;\n\tlet listener;\n\tlet listenerMap;\n\tlet listenerList;\n\tlet singleEventType;\n\n\t// Handler can be passed as\n\t// the second or third argument\n\tif (typeof selector === 'function') {\n\t\tuseCapture = handler;\n\t\thandler = selector;\n\t\tselector = null;\n\t}\n\n\t// If useCapture not set, remove\n\t// all event listeners\n\tif (useCapture === undefined) {\n\t\tthis.off(eventType, selector, handler, true);\n\t\tthis.off(eventType, selector, handler, false);\n\t\treturn this;\n\t}\n\n\tlistenerMap = this.listenerMap[useCapture ? 1 : 0];\n\tif (!eventType) {\n\t\tfor (singleEventType in listenerMap) {\n\t\t\tif (listenerMap.hasOwnProperty(singleEventType)) {\n\t\t\t\tthis.off(singleEventType, selector, handler);\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tlistenerList = listenerMap[eventType];\n\tif (!listenerList || !listenerList.length) {\n\t\treturn this;\n\t}\n\n\t// Remove only parameter matches\n\t// if specified\n\tfor (i = listenerList.length - 1; i >= 0; i--) {\n\t\tlistener = listenerList[i];\n\n\t\tif ((!selector || selector === listener.selector) && (!handler || handler === listener.handler)) {\n\t\t\tthis._removedListeners.push(listener);\n\t\t\tlistenerList.splice(i, 1);\n\t\t}\n\t}\n\n\t// All listeners removed\n\tif (!listenerList.length) {\n\t\tdelete listenerMap[eventType];\n\n\t\t// Remove the main handler\n\t\tif (this.rootElement) {\n\t\t\tthis.rootElement.removeEventListener(eventType, this.handle, useCapture);\n\t\t}\n\t}\n\n\treturn this;\n};\n\n\n/**\n * Handle an arbitrary event.\n *\n * @param {Event} event\n */\nDelegate.prototype.handle = function (event) {\n\tlet i;\n\tlet l;\n\tconst type = event.type;\n\tlet root;\n\tlet phase;\n\tlet listener;\n\tlet returned;\n\tlet listenerList = [];\n\tlet target;\n\tconst eventIgnore = 'ftLabsDelegateIgnore';\n\n\tif (event[eventIgnore] === true) {\n\t\treturn;\n\t}\n\n\ttarget = event.target;\n\n\t// Hardcode value of Node.TEXT_NODE\n\t// as not defined in IE8\n\tif (target.nodeType === 3) {\n\t\ttarget = target.parentNode;\n\t}\n\n\t// Handle SVG <use> elements in IE\n\tif (target.correspondingUseElement) {\n\t\ttarget = target.correspondingUseElement;\n\t}\n\n\troot = this.rootElement;\n\n\tphase = event.eventPhase || (event.target !== event.currentTarget ? 3 : 2);\n\n\t// eslint-disable-next-line default-case\n\tswitch (phase) {\n\t\tcase 1: //Event.CAPTURING_PHASE:\n\t\t\tlistenerList = this.listenerMap[1][type];\n\t\t\tbreak;\n\t\tcase 2: //Event.AT_TARGET:\n\t\t\tif (this.listenerMap[0] && this.listenerMap[0][type]) {\n\t\t\t\tlistenerList = listenerList.concat(this.listenerMap[0][type]);\n\t\t\t}\n\t\t\tif (this.listenerMap[1] && this.listenerMap[1][type]) {\n\t\t\t\tlistenerList = listenerList.concat(this.listenerMap[1][type]);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 3: //Event.BUBBLING_PHASE:\n\t\t\tlistenerList = this.listenerMap[0][type];\n\t\t\tbreak;\n\t}\n\n\tlet toFire = [];\n\n\t// Need to continuously check\n\t// that the specific list is\n\t// still populated in case one\n\t// of the callbacks actually\n\t// causes the list to be destroyed.\n\tl = listenerList.length;\n\twhile (target && l) {\n\t\tfor (i = 0; i < l; i++) {\n\t\t\tlistener = listenerList[i];\n\n\t\t\t// Bail from this loop if\n\t\t\t// the length changed and\n\t\t\t// no more listeners are\n\t\t\t// defined between i and l.\n\t\t\tif (!listener) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\ttarget.tagName &&\n\t\t\t\t[\"button\", \"input\", \"select\", \"textarea\"].indexOf(target.tagName.toLowerCase()) > -1 &&\n\t\t\t\ttarget.hasAttribute(\"disabled\")\n\t\t\t) {\n\t\t\t\t// Remove things that have previously fired\n\t\t\t\ttoFire = [];\n\t\t\t}\n\t\t\t// Check for match and fire\n\t\t\t// the event if there's one\n\t\t\t//\n\t\t\t// TODO:MCG:20120117: Need a way\n\t\t\t// to check if event#stopImmediatePropagation\n\t\t\t// was called. If so, break both loops.\n\t\t\telse if (listener.matcher.call(target, listener.matcherParam, target)) {\n\t\t\t\ttoFire.push([event, target, listener]);\n\t\t\t}\n\t\t}\n\n\t\t// TODO:MCG:20120117: Need a way to\n\t\t// check if event#stopPropagation\n\t\t// was called. If so, break looping\n\t\t// through the DOM. Stop if the\n\t\t// delegation root has been reached\n\t\tif (target === root) {\n\t\t\tbreak;\n\t\t}\n\n\t\tl = listenerList.length;\n\n\t\t// Fall back to parentNode since SVG children have no parentElement in IE\n\t\ttarget = target.parentElement || target.parentNode;\n\n\t\t// Do not traverse up to document root when using parentNode, though\n\t\tif (target instanceof HTMLDocument) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tlet ret;\n\n\tfor (i = 0; i < toFire.length; i++) {\n\t\t// Has it been removed during while the event function was fired\n\t\tif (this._removedListeners.indexOf(toFire[i][2]) > -1) {\n\t\t\tcontinue;\n\t\t}\n\t\treturned = this.fire.apply(this, toFire[i]);\n\n\t\t// Stop propagation to subsequent\n\t\t// callbacks if the callback returned\n\t\t// false\n\t\tif (returned === false) {\n\t\t\ttoFire[i][0][eventIgnore] = true;\n\t\t\ttoFire[i][0].preventDefault();\n\t\t\tret = false;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn ret;\n};\n\n/**\n * Fire a listener on a target.\n *\n * @param {Event} event\n * @param {Node} target\n * @param {Object} listener\n * @returns {boolean}\n */\nDelegate.prototype.fire = function (event, target, listener) {\n\treturn listener.handler.call(target, event, target);\n};\n\n/**\n * Check whether an element\n * matches a tag selector.\n *\n * Tags are NOT case-sensitive,\n * except in XML (and XML-based\n * languages such as XHTML).\n *\n * @param {string} tagName The tag name to test against\n * @param {Element} element The element to test with\n * @returns boolean\n */\nfunction matchesTag(tagName, element) {\n\treturn tagName.toLowerCase() === element.tagName.toLowerCase();\n}\n\n/**\n * Check whether an element\n * matches the root.\n *\n * @param {?String} selector In this case this is always passed through as null and not used\n * @param {Element} element The element to test with\n * @returns boolean\n */\nfunction matchesRoot(selector, element) {\n\tif (this.rootElement === window) {\n\t\treturn (\n\t\t\t// Match the outer document (dispatched from document)\n\t\t\telement === document ||\n\t\t\t// The <html> element (dispatched from document.body or document.documentElement)\n\t\t\telement === document.documentElement ||\n\t\t\t// Or the window itself (dispatched from window)\n\t\t\telement === window\n\t\t);\n\t}\n\treturn this.rootElement === element;\n}\n\n/**\n * Check whether the ID of\n * the element in 'this'\n * matches the given ID.\n *\n * IDs are case-sensitive.\n *\n * @param {string} id The ID to test against\n * @param {Element} element The element to test with\n * @returns boolean\n */\nfunction matchesId(id, element) {\n\treturn id === element.id;\n}\n\n/**\n * Short hand for off()\n * and root(), ie both\n * with no parameters\n *\n * @return void\n */\nDelegate.prototype.destroy = function () {\n\tthis.off();\n\tthis.root();\n};\n\nexport default Delegate;\n","/**\n * Shared 'internal' scope.\n */\nimport {get} from './core/settings.js';\n\n/**\n * CUID Generator\n */\nimport {api as cuid} from '../libs/browser-cuid.js';\n\n/**\n * Record of callbacks to call when a page is tracked.\n */\nconst page_callbacks = [];\n\n/**\n * Log messages to the browser console. Requires 'log' to be set on init.\n *\n * @param {*} args items to log\n * @returns {void}\n */\nfunction log(...args) {\n\tif (get('config').test && window.console) {\n\t\tfor (const arg of args) {\n\t\t\twindow.console.log(arg);\n\t\t}\n\t}\n}\n\n/**\n * Creates a logging function that logs messages to the console with a specified namespace.\n *\n * @function namedLog\n * @param {string} namespace - The namespace to be prefixed to each log message.\n * @returns {function} A function that logs messages to the console with the given namespace if the configuration allows.\n *\n * @example\n * const log = namedLog('MyNamespace');\n * log('This is a message'); \n * // Output: [MyNamespace]: This is a message\n */\nfunction namedLog(namespace) {\n\treturn function(...args) {\n\t\tif(get('config').test && window.console) {\n\t\t\twindow.console.log(`%c[${namespace}]:`, 'color: teal', ...args)\n\t\t}\n\t}\n}\n\n/**\n * Tests if variable is a certain type. Defaults to check for undefined if no type specified.\n *\n * @param {*} variable - The variable to check.\n * @param {string=} type - The type to test for. Defaults to undefined.\n *\n * @returns {boolean} - The answer for if the variable is of type.\n */\nfunction is(variable, type = 'undefined') {\n\treturn typeof variable === type;\n}\n\n/**\n * Merge objects together. Will remove undefined and null values.\n *\n * @param {object} target - The original object to merge in to.\n * @param {object} options - The object to merge into the target. If omitted, will merge target into a new empty Object.\n *\n * @returns {object} The merged object.\n */\nfunction merge(target, options) {\n\tif (!options) {\n\t\toptions = target;\n\t\ttarget = {};\n\t}\n\n\tlet name;\n\tlet src;\n\tlet copy;\n\n\t/* jshint -W089 */\n\t/* eslint guard-for-in: 0 */\n\tfor (name in options) {\n\t\tsrc = target[name];\n\t\tcopy = options[name];\n\n\t\t// Prevent never-ending loop\n\t\tif (target === copy) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Gets rid of missing values too\n\t\tif (typeof copy !== 'undefined' && copy !== null) {\n\t\t\ttarget[name] = src === Object(src) && !is(src, 'function') ? merge(src, copy) : copy;\n\t\t}\n\t}\n\t/* jshint +W089 */\n\t/* jslint forin:true */\n\n\treturn target;\n}\n\n/**\n * URL encode a string.\n *\n * @param {string} str - The string to be encoded.\n * @returns {string} The encoded string.\n */\nfunction encode(str) {\n\tif (window.encodeURIComponent) {\n\t\treturn window.encodeURIComponent(str);\n\t} else {\n\t\treturn window.escape(str);\n\t}\n}\n\n/**\n * URL decode a string.\n *\n * @param {string} str - The string to be decoded.\n * @returns {string} The decoded string.\n */\nfunction decode(str) {\n\tif (window.decodeURIComponent) {\n\t\treturn window.decodeURIComponent(str);\n\t} else {\n\t\treturn window.unescape(str);\n\t}\n}\n\n/**\n * Utility to add event listeners.\n *\n * @param {Element} element\n * @param {string} event\n * @param {EventListenerOrEventListenerObject} listener\n * @returns {void}\n */\nfunction addEvent(element, event, listener) {\n\tif (element.addEventListener) {\n\t\telement.addEventListener(event, listener, false);\n\t} else {\n\t\telement.attachEvent('on' + event, listener);\n\t}\n}\n\n/**\n * Utility for dispatching custom events from window\n *\n * @param {string} namespace\n * @param {string} eventType\n * @param {object} detail\n * @returns {void}\n */\nfunction broadcast(namespace, eventType, detail) {\n\tdetail = detail || {};\n\ttry {\n\t\twindow.dispatchEvent(new CustomEvent(namespace + '.' + eventType, {\n\t\t\tdetail: detail,\n\t\t\tbubbles: true\n\t\t}));\n\t} catch (error) {\n\t\t// empty\n\t}\n}\n\n/**\n * Listen for page tracking requests.\n *\n * @param {Function} cb - The callback to be called whenever a page is tracked.\n * @returns {void}\n */\nfunction onPage(cb) {\n\tif (is(cb, 'function') && !page_callbacks.includes(cb)) {\n\t\tpage_callbacks.push(cb);\n\t}\n}\n\n/**\n * Trigger the 'page' listeners.\n *\n * @returns {void}\n */\nfunction triggerPage() {\n\tfor (let i = 0; i < page_callbacks.length; i++) {\n\t\tpage_callbacks[i]();\n\t}\n}\n\n/**\n * Get a value from document.cookie matching the first match of the regexp you supply\n *\n * @param {RegExp} matcher - The Regex to match with\n * @returns {string} - The vale from the cookie\n */\nfunction getValueFromCookie(matcher) {\n\treturn document.cookie.match(matcher) && RegExp.$1 !== '' && RegExp.$1 !== 'null' ? RegExp.$1 : null;\n}\n\n/**\n * Filter an object to only have the properties which are listed in the `allowlist` parameter.\n *\n * @param {object} objectToFilter - An object whose props need to be filtered\n * @param {Array} allowedPropertyNames - The list of props to allow\n * @returns {object} An object containing only the allowed props\n */\nfunction filterProperties (objectToFilter, allowedPropertyNames) {\n\tconst filteredObject = {};\n\tfor (const allowedName of allowedPropertyNames) {\n\t\tif (objectToFilter[allowedName]) {\n\t\t\tfilteredObject[allowedName] = objectToFilter[allowedName];\n\t\t}\n\t}\n\treturn filteredObject;\n}\n\n/**\n * Trim strings\n *\n * @param {string} str - The string to trim.\n * @returns {string} The trimmed string.\n */\nfunction sanitise (str) {\n\treturn typeof str === 'string' ? str.trim() : str;\n}\n\n/**\n * Assign the subject value if the target properties are undefined\n *\n * @param {object} subject - assign the value\n * @param {object} target - be assigned the value\n * @returns {void}\n */\nfunction assignIfUndefined (subject, target) {\n\tfor (const prop in subject) {\n\t\tif (!target[prop]) {\n\t\t\ttarget[prop] = subject[prop];\n\t\t} else {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.warn(`You can't set a custom property called ${prop}`);\n\t\t}\n\t}\n}\n\n\n/**\n * Identify circular references in 'object', and replace them with a string representation\n * of the reference. Returns a succesfully serialised JSON string, and a list of circular\n * references which were removed.\n * \n * Inspired by https://github.com/sindresorhus/safe-stringify and \n * https://github.com/sindresorhus/decircular\n *\n * @param {*} object The object we want to stringify, and search within for circular references\n * @returns {Object: {jsonString: string, warnings: array}} The stringified object, and a warnings for each circular reference which was removed\n */\nfunction removeCircularReferences(object) {\n\n\t// WeakMaps release memory when all references are garbage-collected\n\tconst circularReferences = new WeakMap();\n\tconst paths = new WeakMap();\n\n\tconst warnings = [];\n\n\tfunction getPathFragment(parent, key) {\n\t\tif (!key) {\n\t\t\treturn '$';\n\t\t}\n\n\t\tif (Array.isArray(parent)) {\n\t\t\treturn `[${key}]`;\n\t\t}\n\n\t\treturn `.${key}`;\n\t}\n\n\tfunction formatCircularReferencesWarning(references) {\n\t\tconst paths = references.map(path => '`' + path.join('') + '`');\n\t\treturn 'Circular reference between ' + paths.join(' AND ');\n\t}\n\n\tfunction replacer(key, value) {\n\t\t// Scalars don't need to be inspected as they can't contain circular references\n\t\tif (!(value !== null && typeof value === 'object')) {\n\t\t\treturn value\n\t\t}\n\n\t\t// Record the path from the root ($) to the current object (value)\n\t\t// in order to print helpful circular reference warnings.\n\t\tconst path = [...paths.get(this) || [], getPathFragment(this, key)];\n\t\tpaths.set(value, path);\n\n\t\t// If a reference to the current value is already in the list, we have\n\t\t// a circular reference. Add the current value to the list along with its path,\n\t\t// and return a useful error string rather than the unserialisable value.\n\t\tif (circularReferences.has(value)) {\n\t\t\tconst references = [...circularReferences.get(value), path];\n\t\t\tcircularReferences.set(value, references);\n\t\t\tconst warning = formatCircularReferencesWarning(references);\n\t\t\twarnings.push(warning);\n\t\t\treturn warning;\n\t\t}\n\n\t\t// This is the first time we've seen the current value in this branch \n\t\t// of the object. Record its path from the object root.\n\t\tcircularReferences.set(value, [path]);\n\n\t\t// Recurse into the value to proactively find circular references\n\t\t// before encountering a loop.\n\t\tconst newValue = Array.isArray(value) ? [] : {};\n\t\tfor (const [k, v] of Object.entries(value)) {\n\t\t\tnewValue[k] = replacer.call(value, k, v);\n\t\t}\n\n\t\t// All circular references to this object will have been identified,\n\t\t// so remove it from the list.\n\t\tcircularReferences.delete(value);\n\n\t\t// This branch of the object can now be safely serialised to a JSON string\n\t\treturn newValue;\n\t}\n\n\tconst jsonString = JSON.stringify(object, replacer);\n\treturn {jsonString, warnings};\n}\n\n\n/**\n * Stringify an object to JSON, removing any circular references. When circular references\n * are found, an error is thrown in a new event loop so that global error handlers can report it.\n *\n * @param {*} object The object we want to stringify, and search within for circular references\n * @returns {string} The safely stringified JSON string\n */\nfunction safelyStringifyJson(object) {\n\n\t// JSON.stringify throws on two cases:\n\t// - value contains a circular reference\n\t// - A BigInt value is encountered\n\t// Circular references are a real possibility in the way o-tracking is called (and saves a queue of \n\t// messages in a store), so we need to handle those gracefully.\n\t// \n\t// However, for performance reasons, we always attempt to do a basic JSON.stringify() first. The \n\t// recursion involved in removeCircularReferences() makes it about 20x slower to stringify a basic payload. \n\t// This performance hit will be exacerbated on slow devices (e.g. old Android phones) with lots of queued offline events.\n\ttry {\n\t\treturn JSON.stringify(object);\n\n\t// NB: error is discarded - we have more work to do in order to throw a useful message\n\t} catch (error) {\n\t\n\t\tconst {jsonString, warnings} = removeCircularReferences(object);\n\t\n\t\tif (warnings.length) {\n\t\t\t// Throw in a new event loop, as we always want to return JSON so the tracking payload is sent\n\t\t\tsetTimeout(() => {\n\t\t\t\tconst errorMessage = \"AssertionError: o-tracking does not support circular references in the analytics data.\\n\" +\n\t\t\t\t\"Please remove the circular references in the data.\\n\" +\n\t\t\t\t\"Here are the paths in the data which are circular:\\n\" +\n\t\t\t\twarnings.join('\\n');\n\t\t\t\tthrow new Error(errorMessage);\n\t\t\t});\n\t\t}\n\t\n\t\treturn jsonString;\n\t}\n\n\n};\n\n/**\n * Find out whether two objects are deeply equal to each other.\n *\n * @param {*} a\n * @param {*} b\n * @returns {boolean} - true if the two arguments are deeply equal\n */\nfunction isDeepEqual(a, b) {\n\tif (a === b) {\n\t\treturn true;\n\t}\n\n\tif (\n\t\ta &&\n\t\tb &&\n\t\ttypeof a === \"object\" &&\n\t\ttypeof b === \"object\"\n\t) {\n\t\tif (a.constructor !== b.constructor) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (Array.isArray(a)) {\n\t\t\tconst length = a.length;\n\t\t\tif (length !== b.length) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tfor (let i = length; i-- !== 0; ) {\n\t\t\t\tif (!isDeepEqual(a[i], b[i])) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tif (a.constructor === RegExp) {\n\t\t\treturn (\n\t\t\t\ta.source === b.source && a.flags === b.flags\n\t\t\t);\n\t\t}\n\t\tif (a.valueOf !== Object.prototype.valueOf) {\n\t\t\treturn a.valueOf() === b.valueOf();\n\t\t}\n\t\tif (a.toString !== Object.prototype.toString) {\n\t\t\treturn a.toString() === b.toString();\n\t\t}\n\n\t\tconst keys = Object.keys(a);\n\t\tconst length = keys.length;\n\t\tif (length !== Object.keys(b).length) {\n\t\t\treturn false;\n\t\t}\n\n\t\tfor (let i = length; i-- !== 0; ) {\n\t\t\tif (!Object.prototype.hasOwnProperty.call(b, keys[i])) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tfor (let i = length; i-- !== 0; ) {\n\t\t\tconst key = keys[i];\n\n\t\t\tif (!isDeepEqual(a[key], b[key])) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n}\n\nexport {\n\tlog,\n\tnamedLog,\n\tis,\n\tis as isUndefined,\n\tmerge,\n\tencode,\n\tdecode,\n\tcuid as guid,\n\taddEvent,\n\tbroadcast,\n\tonPage,\n\ttriggerPage,\n\tgetValueFromCookie,\n\tsanitise,\n\tassignIfUndefined,\n\tfilterProperties,\n\tremoveCircularReferences,\n\tsafelyStringifyJson,\n\tisDeepEqual\n};\n","export const LogLevel = Object.freeze({\n DEBUG: 0,\n INFO: 1,\n WARN: 2,\n ERROR: 3,\n TEST: 4,\n DEFAULT: 2,\n});\n\nexport function convertStringLogLevel(value: string | null) {\n const level = value?.toLowerCase();\n\n if (level === \"debug\") {\n return LogLevel.DEBUG;\n }\n\n if (level === \"info\") {\n return LogLevel.INFO;\n }\n\n if (level === \"warn\") {\n return LogLevel.WARN;\n }\n\n if (level === \"error\") {\n return LogLevel.ERROR;\n }\n\n if (level === \"test\") {\n return LogLevel.TEST;\n }\n\n return LogLevel.DEFAULT;\n}\n\nexport class Logger {\n level: number;\n constructor(\n { level = LogLevel.DEFAULT }: { level: number } = {\n level: LogLevel.DEFAULT,\n }\n ) {\n this.level = level;\n }\n\n debug(...args: any[]) {\n if (this.level <= LogLevel.DEBUG) {\n console.info(...args);\n }\n }\n\n log = this.debug;\n\n info(...args: any[]) {\n if (this.level <= LogLevel.INFO) {\n console.info(...args);\n }\n }\n\n warn(...args: any[]) {\n if (this.level <= LogLevel.WARN) {\n console.warn(...args);\n }\n }\n\n error(...args: any[]) {\n if (this.level <= LogLevel.ERROR) {\n console.error(...args);\n }\n }\n}\n","// Trace the element and all of its parents, collecting properties as we go\nimport {\n sanitise,\n assignIfUndefined,\n} from \"@financial-times/o-tracking/src/javascript/utils\";\n\ntype PropMap = { [k: string]: any };\n// For a given container element, get the number of elements that match the\n// original element (siblings); and the index of the original element (position).\nconst getSiblingsAndPosition = (\n el: Element | null,\n originalEl: Element,\n selector: string\n) => {\n const siblings = Array.from(el?.querySelectorAll(selector) ?? []);\n const position = siblings.findIndex((item) => item === originalEl);\n if (position === -1) {\n return;\n }\n return {\n siblings: siblings.length,\n position,\n };\n};\n\nconst elementPropertiesToCollect = [\n \"nodeName\",\n \"className\",\n \"id\",\n \"href\",\n \"text\",\n \"role\",\n];\n// Get all (sanitised) properties of a given element.\nconst getAllElementProperties = (element: any) => {\n const properties: PropMap = {};\n for (const property of elementPropertiesToCollect) {\n const value =\n element[property] ||\n element.getAttribute(property) ||\n element.hasAttribute(property);\n if (value !== undefined) {\n if (typeof value === \"boolean\") {\n properties[property] = value;\n } else {\n properties[property] = sanitise(value);\n }\n }\n }\n\n return properties;\n};\n\nconst parseRawValue = (rawValue: string) => {\n try {\n const parsedValue = JSON.parse(rawValue);\n const type = Object.prototype.toString.call(parsedValue);\n const isJSON = type === \"[object Object]\" || type === \"[object Array]\";\n\n return [isJSON, parsedValue];\n } catch (error) {\n return [false, null];\n }\n};\n\nconst getAttributeValue = (rawValue: string) => {\n const [isJSON, value] = parseRawValue(rawValue);\n\n return isJSON ? value : rawValue;\n};\n\n// Get some properties of a given element.\nconst getDomPathProps = (attrs: Attr[], props: PropMap) => {\n // Collect any attribute that matches given strings.\n attrs\n .filter((attribute) =>\n attribute.name.match(/^data-trackable|^data-o-|^aria-/i)\n )\n .forEach((attribute) => {\n props[attribute.name] = attribute.value;\n });\n\n return props;\n};\n\n// Get only the custom data-trackable-context-? properties of a given element\nconst getContextProps = (\n attrs: Attr[],\n props: PropMap,\n isOriginalEl: boolean\n) => {\n const customProps: { [k: string]: any } = {};\n\n // for the original element collect properties like className, nodeName\n if (isOriginalEl) {\n elementPropertiesToCollect.forEach((name) => {\n if (typeof props[name] !== \"undefined\" && name !== \"id\") {\n customProps[name] = props[name];\n }\n });\n }\n\n // Collect any attribute that matches given strings.\n attrs\n .filter((attribute) => attribute.name.match(/^data-trackable-context-/i))\n .forEach((attribute) => {\n customProps[attribute.name.replace(\"data-trackable-context-\", \"\")] =\n getAttributeValue(attribute.value);\n });\n\n return customProps;\n};\n\nexport function getTrace(el: Element, rootEl: Element) {\n const originalEl = el;\n const selector = originalEl?.getAttribute(\"data-trackable\")\n ? `[data-trackable=\"${originalEl.getAttribute(\"data-trackable\")}\"]`\n : originalEl?.nodeName;\n const trace = [];\n const customContext = {};\n while (el && el !== rootEl) {\n const props = getAllElementProperties(el);\n const attrs = Array.from(el.attributes);\n let domPathProps = getDomPathProps(attrs, props);\n\n // If the element happens to have a data-trackable attribute, get the siblings\n // and position of the element (relative to the current element).\n if (domPathProps[\"data-trackable\"]) {\n domPathProps = Object.assign(\n domPathProps,\n getSiblingsAndPosition(el, originalEl, selector)\n );\n }\n\n trace.push(domPathProps);\n\n const contextProps = getContextProps(attrs, props, el === originalEl);\n\n assignIfUndefined(contextProps, customContext);\n\n el = el.parentNode as Element;\n }\n return { trace, customContext };\n}\n","import Delegate from \"ftdomdelegate/main\";\n\nimport {\n sanitise,\n assignIfUndefined,\n} from \"@financial-times/o-tracking/src/javascript/utils\";\nimport { Logger } from \"./logger\";\nimport { getTrace } from \"./get-trace\";\n\nconst eventPropertiesToCollect = [\"ctrlKey\", \"altKey\", \"shiftKey\", \"metaKey\"];\n\nclass Tracking {\n cccId: string;\n cccName: string;\n subtype: string;\n teamName: string;\n shadowRoot: ShadowRoot | null;\n category: string;\n elements: string | string[];\n isInitialised: boolean;\n log: Logger;\n\n constructor({\n id = \"00000000-0000-0000-0000-000000000000\",\n name = \"ccc-component\",\n subtype = \"interactive\",\n teamName = \"djd\",\n shadowRoot = null,\n category = \"cta\",\n elements = 'a, button, input, [role=\"button\"]',\n logger,\n }: {\n id?: string;\n name: string;\n subtype: string;\n teamName?: string;\n shadowRoot: ShadowRoot | null;\n category?: string;\n elements?: string | string[];\n logger: Logger;\n }) {\n this.cccId = id;\n this.cccName = name;\n this.subtype = subtype;\n this.teamName = teamName;\n this.shadowRoot = shadowRoot;\n this.category = category;\n this.elements = elements;\n this.isInitialised = false;\n this.log = logger ?? new Logger();\n }\n\n // Get properties for the event (as opposed to properties of the clicked element)\n getEventProperties(event: any) {\n const eventProperties: { [k: string]: any } = {};\n for (const property of eventPropertiesToCollect) {\n if (event[property]) {\n try {\n eventProperties[property] = sanitise(event[property]);\n } catch (e) {\n this.log.info(e);\n }\n }\n }\n return eventProperties;\n }\n\n // Controller for handling click events\n handleClickEvent(\n eventData: { action: string; category: string },\n root: Element\n ) {\n return (clickEvent: Event, clickElement: HTMLElement) => {\n const context: any = this.getEventProperties(clickEvent);\n const { trace, customContext } = getTrace(clickElement, root);\n context.custom =\n clickElement.dataset && clickElement.dataset.custom\n ? JSON.parse(clickElement.dataset.custom)\n : null;\n context.domPathTokens = trace;\n context.component = {\n id: this.cccId,\n name: this.cccName,\n type: \"custom-code-component\",\n subtype: this.subtype,\n };\n context.teamName = this.teamName;\n context.url = document.URL;\n\n assignIfUndefined(customContext, context);\n\n context.method = \"ftCustomAnalytics\";\n eventData = { ...eventData, ...context };\n\n // send spoor event\n document.body.dispatchEvent(\n new CustomEvent(\"oTracking.event\", {\n detail: eventData,\n bubbles: true,\n composed: true,\n })\n );\n };\n }\n\n sendSpoorEvent(triggerAction: any, extraDetail: any) {\n const eventData = {\n category: \"component\",\n action: \"act\",\n component: {\n id: this.cccId,\n name: this.cccName,\n type: \"custom-code-component\",\n subtype: this.subtype,\n },\n teamName: this.teamName,\n trigger_action: triggerAction,\n custom: extraDetail,\n method: \"ftCustomAnalytics\",\n };\n\n // send spoor event\n document.body.dispatchEvent(\n new CustomEvent(\"oTracking.event\", {\n detail: eventData,\n bubbles: true,\n composed: true,\n })\n );\n }\n\n init(id: string) {\n if (!this.isInitialised) {\n this.isInitialised = true;\n this.cccId = id ? id : this.cccId;\n\n const eventData = {\n action: \"click\",\n category: this.category,\n };\n\n const root = this.shadowRoot?.querySelector(\"[data-component-root]\");\n\n if (root) {\n const shadowDelegate = new Delegate(root);\n shadowDelegate.on(\n \"click\",\n this.elements,\n this.handleClickEvent(eventData, root),\n true\n );\n }\n }\n }\n}\n\nexport default Tracking;\n","import { CCCError } from \"./errors\";\n\nexport type ComponentPathType = {\n org: string;\n repo: string;\n component: string;\n versionRange: string;\n};\nexport class ComponentPath {\n org: string;\n repo: string;\n component: string;\n versionRange: string;\n\n constructor(path: ComponentPathType | string) {\n const { org, repo, component, versionRange } = isValidComponentPathObject(\n path\n )\n ? path\n : ComponentPath.fromString(path);\n this.org = org;\n this.repo = repo;\n this.component = component;\n this.versionRange = versionRange;\n }\n\n set path(path: ComponentPathType | string) {\n const { org, repo, component, versionRange } = isValidComponentPathObject(\n path\n )\n ? path\n : ComponentPath.fromString(path);\n this.org = org;\n this.repo = repo;\n this.component = component;\n this.versionRange = versionRange;\n }\n\n get path(): string {\n return `${this.org}/${this.repo}@${this.versionRange}/${this.component}`;\n }\n\n toString(): string {\n return this.path;\n }\n\n static fromString(path: string | null, v?: string | null): ComponentPath {\n if (!path) throw new CCCError(\"No path specified\");\n\n const versionRange =\n v ??\n path\n .match(/@[^\\/]+/)\n ?.toString()\n .replace(\"@\", \"\") ??\n \"unknown\";\n\n if (!versionRange) throw new CCCError(\"No version specified\");\n\n const [component, repo, org] = path\n .replace(/@[^\\/]+/, \"\")\n .split(\"/\")\n .reverse();\n\n return new ComponentPath({ org, repo, component, versionRange });\n }\n}\n\nexport type DetailType = {\n component: ComponentPath;\n source?: string;\n cause?: string;\n};\n\nexport function isValidComponentPathObject(\n value: unknown\n): value is ComponentPathType {\n if (typeof value === \"object\" && value !== null) {\n return \"org\" in value && \"repo\" in value && \"component\" in value;\n }\n\n return false;\n}\n","/**\n * This is the base CCC component error class. These are raised when the component being loaded errors\n */\n\nimport { ComponentPath, DetailType, isValidComponentPathObject } from \"./path\";\n\nexport class CCCError extends Error {\n component: ComponentPath | null;\n source?: string;\n constructor(message: string | null, detail?: DetailType) {\n if (!detail && message) {\n super(message);\n this.component = null;\n } else if (typeof detail?.component === \"string\") {\n super(\n message ??\n `${detail.cause ?? \"Unknown error\"} in ${detail.component} imported from ${detail.source ?? \"an undefined source\"}.`\n );\n\n this.component = ComponentPath.fromString(detail.component);\n } else if (isValidComponentPathObject(detail?.component)) {\n super(\n message ??\n `${detail.cause ?? \"Unknown error\"} in ${detail.component.org}/${detail.component.repo}/${detail.component.component}@${detail.component.versionRange} imported from ${detail.source ?? \"an undefined source\"}.`\n );\n this.component = new ComponentPath(detail.component);\n } else {\n super(\n `${detail?.cause ?? \"Unknown error\"} in unknown component imported from ${detail?.source ?? \"unknown source\"}.`\n );\n this.component = null;\n }\n\n this.source = detail?.source;\n\n // Maintains proper stack trace for where our error was thrown (only available on V8)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, CCCError);\n }\n\n this.name = \"CCCError\";\n }\n}\n\n/**\n * This class is used to raise errors that occur during the import of the CCC component app\n */\nexport class CCCImportError extends CCCError {\n constructor(message: string, detail: DetailType) {\n super(message, { ...detail, cause: \"Import error\" });\n this.name = \"CCCImportError\";\n }\n}\n\n/**\n * This class is used to raise errors that occur during the rendering of the CCC component app\n */\nexport class CCCRenderError extends CCCError {\n constructor(message: string, detail: DetailType) {\n super(message, { ...detail, cause: \"Render error\" });\n this.name = \"CCCRenderError\";\n }\n}\n\n/**\n * This class is used to raise errors that occur as a result of the CCC component app timing out\n */\nexport class CCCTimeoutError extends CCCError {\n constructor(detail: DetailType) {\n super(null, { ...detail, cause: \"Timeout error\" });\n this.name = \"CCCTimeoutError\";\n }\n}\n","import { ComponentPath } from \"./path\";\n\nexport class CCCConnectedEvent extends Event {\n static eventType = \"ccc:ConnectedEvent\";\n\n component: ComponentPath;\n source?: string;\n\n constructor(\n detail: { component: ComponentPath; source?: string },\n opts?: EventInit\n ) {\n super(CCCConnectedEvent.eventType, {\n bubbles: true,\n cancelable: false,\n composed: true,\n ...opts,\n });\n this.component = detail.component;\n this.source = detail.source;\n }\n}\n","/**\n * Used to convert camelCase to kebab-case\n * @param str\n * @returns\n */\nexport const kebabize = (str: string) =>\n str.replace(\n /[A-Z]+(?![a-z])|[A-Z]/g,\n ($, ofs) => (ofs ? \"-\" : \"\") + $.toLowerCase()\n );\n\n/**\n * Checks if the provided host is part of the allowed test environments.\n *\n * @param host - The hostname to check.\n * @returns True if the hostname is a safe test environment, false otherwise.\n */\nexport function isSafeTestEnv(host: string | undefined) {\n return isAllowed([\n 'localhost',\n 'local.ft.com',\n /^.*\\.apps\\.in\\.ft\\.com$/,\n ], host);\n}\n\n/**\n * Checks if the current window location hostname is considered a local environment.\n *\n * @returns True if the hostname is local, false otherwise.\n */\nexport function isLocalEnv() {\n return isAllowed([\n 'localhost',\n 'local.ft.com',\n /^.*\\.in\\.ft\\.com$/,\n ], window.location.hostname);\n}\n\n/**\n * Checks if the current window location host is one of the Spark environments.\n *\n * @returns True if the host is spark.ft.com or spark-staging.ft.com, false otherwise.\n */\nexport function isSparkEnv() {\n return isAllowed([\n 'spark.ft.com',\n 'spark-staging.ft.com',\n ], window.location.host);\n}\n\n/**\n * Checks if the given hostname is in the provided allowlist.\n *\n * @param allowlist - A list of allowed hostnames or RegExp matchers.\n * @param hostname - The hostname to validate.\n * @returns True if the hostname matches any item in the allowlist, false otherwise.\n */\nexport function isAllowed(allowlist: (string|RegExp)[], hostname: string | undefined) {\n if (!hostname) return false;\n return allowlist.some(item => {\n if (typeof item === 'string') {\n return item === hostname;\n }\n return item.test(hostname);\n });\n} \n","import { isLocalEnv, isSafeTestEnv, isSparkEnv } from \"./util\"\n\n\n/**\n * Assigns a test URL based on the provided testEnv value.\n *\n * @param testEnv - A string indicating test environment setting\n * @returns A `URL` object if valid and safe, or `undefined` if invalid.\n */\nexport function assignTestURL(testEnv: string | null): URL | undefined {\n if (testEnv === null) {\n return\n }\n\n let testUrl\n const defaultTestUrl = new URL('http://localhost:5173')\n\n try {\n if (typeof testEnv === 'string') {\n if ((testEnv === '' || testEnv.toLowerCase() === 'true') && isLocalEnv()) {\n testUrl = defaultTestUrl\n } else {\n const hasProtocol = testEnv.startsWith('http://') || testEnv.startsWith('https://')\n testUrl = hasProtocol ? new URL(testEnv) : undefined\n\n // Prevent script injection\n if (testUrl && !isSafeTestEnv(testUrl?.hostname)) {\n throw new Error(\"Unsafe testing host override\");\n }\n }\n } else if (isSparkEnv()) {\n testUrl = defaultTestUrl;\n }\n } catch (_) {\n return testUrl\n }\n\n return testUrl\n}\n\n/**\n * Checks whether the given test URL can establish a successful WebSocket connection,\n * which indicates a live test environment (e.g., Vite HMR is active).\n *\n * @param testUrl - The test environment URL to check.\n * @returns A promise that resolves to true if WebSocket connection is open, otherwise false.\n */\nexport async function useComponentTestEnv(testUrl?: URL): Promise<boolean> {\n if (!testUrl) {\n return false\n }\n\n function checkWebSocketOpen(host: string): Promise<boolean> {\n try {\n return new Promise<boolean>((res) => {\n const socket = new WebSocket(`ws://${host}`, \"vite-hmr\");\n \n const timer = setTimeout(() => {\n res(socket.readyState === WebSocket.OPEN);\n socket.close();\n }, 50);\n \n socket.addEventListener(\"error\", () => {\n clearTimeout(timer);\n socket.close();\n res(false);\n }, { once: true });\n });\n } catch (err) {\n return Promise.resolve(false);\n }\n }\n\n const isWebSocketOpen = await checkWebSocketOpen(testUrl?.host);\n\n return isWebSocketOpen\n}","/**\n * @file\n * Main component definition for custom-code-component\n */\n\nimport type { ContentTree } from \"@financial-times/content-tree\";\nimport { BaseRenderer } from \"../../ccc-sdk/src/renderers/BaseRenderer\";\nimport Tracking from \"./tracking\";\nimport { convertStringLogLevel, Logger } from \"./logger\";\nimport {\n CCCError,\n CCCImportError,\n CCCRenderError,\n CCCTimeoutError,\n} from \"./errors\";\nimport { CCCConnectedEvent } from \"./events\";\nimport { ComponentPath } from \"./path\";\nimport { kebabize } from \"./util\";\nimport { assignTestURL, useComponentTestEnv } from \"./environment\";\n\nexport class FTCustomCodeComponent extends HTMLElement {\n app?: typeof BaseRenderer.prototype.render;\n mode: \"closed\" | \"open\" = \"open\";\n RESERVED_ATTRS = new Set([\n \"iframe\",\n \"path\",\n \"version\",\n \"data-component-props\",\n \"data-asset-type\",\n \"shadow-open\",\n \"env\",\n \"load-timeout\",\n ]);\n\n source?: string;\n tracking?: Tracking;\n lightRoot?: ChildNode[];\n component?: ComponentPath;\n\n log: Logger;\n\n constructor() {\n super();\n this.log = new Logger({\n level: convertStringLogLevel(this.getAttribute(\"log\")),\n });\n\n const supportsDeclarative =\n HTMLElement.prototype.hasOwnProperty(\"attachInternals\");\n\n try {\n const internals = supportsDeclarative && this.attachInternals();\n } catch (e) {\n this.log.error(e);\n }\n }\n\n async connectedCallback() {\n try {\n const path = this.getAttribute(\"path\");\n const versionRange = this.getAttribute(\"version\");\n this.component = ComponentPath.fromString(path, versionRange);\n \n // Backup the light root to restore in case of error\n this.lightRoot = Array.from(this.childNodes);\n this.app = await this.load();\n await this.mount();\n await this.initTracking();\n } catch (e) {\n if (e instanceof Error) {\n requestAnimationFrame(() => {\n this.emitError(e);\n });\n }\n\n this.unmount(e as Error);\n }\n }\n\n emitError(error: Error) {\n let errorEvent;\n\n if (error instanceof CCCError && error.name?.startsWith(\"CCC\")) {\n errorEvent = error.name.replace(/^CCC/, \"ccc:\");\n } else {\n errorEvent = `ccc:${error?.name ?? \"UnknownError\"}`;\n }\n\n if (!errorEvent) {\n return this.log.debug(error);\n }\n\n this.dispatchEvent(\n new ErrorEvent(errorEvent, {\n bubbles: true,\n cancelable: false,\n composed: true,\n error,\n message: error.message,\n })\n );\n }\n\n disconnectedCallback() {\n const path = this.getAttribute(\"path\");\n this.log.info(`<custom-code-component:${path}> disconnected`);\n if (typeof this.onunmount === \"function\") this.onunmount();\n }\n\n channel = new MessageChannel();\n\n onmessage() {}\n onunmount(root?: any) {}\n async onready(app: Promise<void>) {\n try {\n await app;\n } catch (e) {\n if (e instanceof Error) this.emitError(e);\n }\n }\n\n postMessage(event: any) {\n this.channel.port1.postMessage(event);\n }\n\n async mount(prerendered?: ShadowRoot | null) {\n try {\n this.mode =\n this.getAttribute(\"shadow-open\") == \"false\" ? \"closed\" : \"open\";\n if (this.component) {\n\n this.dispatchEvent(\n new CCCConnectedEvent({\n component: this.component,\n source: this.source,\n })\n );\n\n this.dataset.cccReady = \"true\";\n delete this.dataset.cccError;\n \n\n if (!this.app) {\n throw new Error(\"CCC mounted without App\");\n }\n\n const ssr = this.shadowRoot !== null;\n const shadow = this.shadowRoot ?? this.attachShadow({ mode: this.mode });\n\n const data = JSON.parse(this.getAttribute(\"data-component-props\")!);\n\n const extraProps = Object.fromEntries(\n [...this.attributes]\n .filter((attribute) => !this.RESERVED_ATTRS.has(attribute.name))\n .map((attribute) => [attribute.name, attribute.value])\n );\n\n // Create tracking instance\n this.tracking = new Tracking({\n name: this.component?.toString(),\n subtype: \"interactive\",\n teamName: \"djd\",\n shadowRoot: this.shadowRoot,\n logger: this.log,\n });\n\n const { unmount, onmessage, ready } =\n this.app(\n shadow,\n {\n ...extraProps,\n data,\n port: this.channel.port2,\n tracking: this.tracking,\n prerendered: !!prerendered,\n children: this.children,\n },\n ssr\n ) || {};\n\n if (unmount) this.onunmount = unmount;\n if (onmessage) this.onmessage = onmessage;\n if (ready) this.onready(ready);\n }\n } catch (err) {\n this.log.info(\n `<custom-code-component> uncaught error during mount from ${this.component?.toString()}`\n );\n this.log.error(err);\n\n throw err;\n }\n }\n\n // Called in top-level error handler\n // Replace shadow root with light DOM children on error\n unmount(e: Error) {\n if (this.lightRoot) {\n this.onunmount();\n this.shadowRoot?.replaceChildren(...this.lightRoot);\n \n if (!this.dataset.cccError)\n this.dataset.cccError = kebabize(e.name.replace(\"CCC\", \"\"));\n delete this.dataset.cccReady;\n }\n }\n\n async load() {\n if (!this.component) {\n throw new Error(\"No path found\")\n }\n const path = this.getAttribute(\"path\");\n const componentVersionRange = this.getAttribute(\"version\");\n const timeout = Number(this.getAttribute(\"load-timeout\") || 10000);\n const testEnv = this.getAttribute(\"testEnv\")\n const testUrl = assignTestURL(testEnv)\n const isTestEnv = await useComponentTestEnv(testUrl)\n\n const id = this.getAttribute(\"id\");\n // id querystring necessary to multiple allow components with the same source (same name and version number) to appear on the page correctly\n this.source = isTestEnv\n ? `${testUrl?.origin}/src/${this.component.component}/index.jsx?id=${id}`\n : `https://www.ft.com/__component/${this.component.org}/${this.component.repo}${\n componentVersionRange ? `@${componentVersionRange}` : \"@latest\"\n }/${this.component.component}/${this.component.component}.js?id=${id}`;\n\n try {\n return await new Promise<typeof BaseRenderer.prototype.render>(\n (resolve, reject) => {\n const to = setTimeout(() => {\n this.log.error(\"CCC import timeout error\");\n reject(\n new CCCTimeoutError({\n component: this.component!,\n source: this.source,\n })\n );\n }, Number(timeout));\n\n if (this.source) {\n import(/* webpackIgnore: true */ this.source /* @vite-ignore */)\n .then(({ default: componentRenderFunction }) => {\n if (componentRenderFunction) {\n clearTimeout(to);\n resolve(componentRenderFunction);\n } else\n throw new CCCImportError(\n \"No component renderer default export found\",\n {\n component: this.component!,\n source: this.source,\n }\n );\n })\n .catch((e) => {\n clearTimeout(to);\n this.log.error(e);\n if (e instanceof Error && !(e instanceof CCCImportError)) {\n reject(\n new CCCImportError(e.message, {\n component: this.component!,\n source: this.source,\n })\n );\n } else {\n reject(e);\n }\n });\n } else {\n clearTimeout(to);\n throw new CCCImportError(`Unable to mount ${path}`, {\n component: this.component!,\n source: this.source,\n });\n }\n }\n );\n } catch (err) {\n this.log.error(\n `<custom-code-component> error during import from ${path}@${componentVersionRange}`\n );\n\n throw err;\n }\n }\n\n initTracking = async () => {\n try {\n this.tracking?.init(this.id);\n } catch (e) {\n const path = this.getAttribute(\"path\");\n const componentVersionRange = this.getAttribute(\"version\");\n this.log.info(\n `Error initialising tracking on <custom-code-component> ${path}@${componentVersionRange}`\n );\n this.log.error(e);\n }\n };\n}\n\nexport interface CustomCodeComponent extends ContentTree.Node {\n type: \"CustomCodeComponent\";\n path: string;\n versionRange: string;\n altText: string;\n lastModified: string;\n fallbackImage?: ContentTree.Image;\n displayFallbackText: boolean;\n layout: \"in-line\" | \"mid-grid\" | \"full-grid\" | \"full-bleed\";\n /* prettier-ignore */\n attributes: { \n [key: string]: string | boolean | undefined;\n } | { children?: CustomCodeComponent | Array<CustomCodeComponent> };\n}\n\nexport type { FTCustomCodeComponent as CCCHTMLElement };\n","import { FTCustomCodeComponent } from \"./custom-code-component\";\n\n// Register the custom element\nexport const init = () =>\n customElements.define(\"custom-code-component\", FTCustomCodeComponent);\n\n// Allows module to be imported multiple times but custom element only registered once\nif (customElements && !customElements.get(\"custom-code-component\")) init();\n"],"names":["Delegate","root","listenerMap","eventType","selector","handler","useCapture","matcher","matcherParam","matchesTag","matchesId","matchesRoot","i","listener","listenerList","singleEventType","event","l","type","phase","returned","target","eventIgnore","toFire","ret","tagName","element","id","sanitise","str","assignIfUndefined","subject","prop","LogLevel","convertStringLogLevel","value","level","Logger","args","getSiblingsAndPosition","el","originalEl","siblings","position","item","elementPropertiesToCollect","getAllElementProperties","properties","property","parseRawValue","rawValue","parsedValue","getAttributeValue","isJSON","getDomPathProps","attrs","props","attribute","getContextProps","isOriginalEl","customProps","name","getTrace","rootEl","trace","customContext","domPathProps","contextProps","eventPropertiesToCollect","Tracking","subtype","teamName","shadowRoot","category","elements","logger","eventProperties","e","eventData","clickEvent","clickElement","context","triggerAction","extraDetail","_a","ComponentPath","path","org","repo","component","versionRange","isValidComponentPathObject","v","CCCError","message","detail","__super","CCCImportError","CCCTimeoutError","_CCCConnectedEvent","opts","CCCConnectedEvent","kebabize","$","ofs","isSafeTestEnv","host","isAllowed","isLocalEnv","isSparkEnv","allowlist","hostname","assignTestURL","testEnv","testUrl","defaultTestUrl","useComponentTestEnv","checkWebSocketOpen","res","socket","timer","FTCustomCodeComponent","componentVersionRange","supportsDeclarative","internals","error","errorEvent","app","prerendered","_b","ssr","shadow","data","extraProps","unmount","onmessage","ready","err","timeout","isTestEnv","resolve","reject","to","componentRenderFunction","init"],"mappings":"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","x_google_ignoreList":[0,1]}