@phantomstudios/ft-lib 0.5.1 → 0.5.2-rc10
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/lib/cmp/loadFtCmp.d.ts +1 -0
- package/lib/cmp/loadFtCmp.d.ts.map +1 -1
- package/lib/cmp/loadFtCmp.js +6 -4
- package/lib/cmp/loadFtCmp.js.map +1 -1
- package/lib/cmp/vendorConsent.d.ts +9 -0
- package/lib/cmp/vendorConsent.d.ts.map +1 -0
- package/lib/cmp/vendorConsent.js +90 -0
- package/lib/cmp/vendorConsent.js.map +1 -0
- package/lib/consentMonitor/index.d.ts +4 -0
- package/lib/consentMonitor/index.d.ts.map +1 -1
- package/lib/consentMonitor/index.js +30 -8
- package/lib/consentMonitor/index.js.map +1 -1
- package/package.json +2 -2
- package/src/cmp/loadFtCmp.ts +6 -3
- package/src/cmp/vendorConsent.ts +119 -0
- package/src/consentMonitor/index.ts +33 -16
- package/src/types.d.ts +28 -1
package/lib/cmp/loadFtCmp.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loadFtCmp.d.ts","sourceRoot":"","sources":["../../src/cmp/loadFtCmp.ts"],"names":[],"mappings":"AAAA,wBAAgB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAoB/C;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"loadFtCmp.d.ts","sourceRoot":"","sources":["../../src/cmp/loadFtCmp.ts"],"names":[],"mappings":"AAAA,wBAAgB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAoB/C;AAED,wBAAgB,YAAY,IAAI,IAAI,CAGnC;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,CAGvD"}
|
package/lib/cmp/loadFtCmp.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.loadFtCmpScript = loadFtCmpScript;
|
|
4
|
+
exports.initCmpQueue = initCmpQueue;
|
|
4
5
|
exports.enqueueCmpCallback = enqueueCmpCallback;
|
|
5
6
|
function loadFtCmpScript() {
|
|
6
7
|
if (document.getElementById("ft-cmp-loader")) {
|
|
@@ -21,11 +22,12 @@ function loadFtCmpScript() {
|
|
|
21
22
|
document.head.appendChild(script);
|
|
22
23
|
});
|
|
23
24
|
}
|
|
25
|
+
function initCmpQueue() {
|
|
26
|
+
window._sp_ = window._sp_ || {};
|
|
27
|
+
window._sp_queue = window._sp_queue || [];
|
|
28
|
+
}
|
|
24
29
|
function enqueueCmpCallback(cb) {
|
|
25
|
-
|
|
26
|
-
window._sp_ = {};
|
|
27
|
-
if (!window._sp_queue)
|
|
28
|
-
window._sp_queue = [];
|
|
30
|
+
initCmpQueue();
|
|
29
31
|
window._sp_queue.push(cb);
|
|
30
32
|
}
|
|
31
33
|
//# sourceMappingURL=loadFtCmp.js.map
|
package/lib/cmp/loadFtCmp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loadFtCmp.js","sourceRoot":"","sources":["../../src/cmp/loadFtCmp.ts"],"names":[],"mappings":";;AAAA,0CAoBC;AAED,
|
|
1
|
+
{"version":3,"file":"loadFtCmp.js","sourceRoot":"","sources":["../../src/cmp/loadFtCmp.ts"],"names":[],"mappings":";;AAAA,0CAoBC;AAED,oCAGC;AAED,gDAGC;AA9BD,SAAgB,eAAe;IAC7B,IAAI,QAAQ,CAAC,cAAc,CAAC,eAAe,CAAC,EAAE,CAAC;QAC7C,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;IAED,OAAO,IAAI,OAAO,CAAO,UAAC,OAAO,EAAE,MAAM;QACvC,IAAM,MAAM,GAAsB,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QACnE,MAAM,CAAC,EAAE,GAAG,eAAe,CAAC;QAC5B,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC;QACpB,MAAM,CAAC,GAAG,GAAG,sCAAsC,CAAC;QACpD,MAAM,CAAC,cAAc,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;YAClE,CAAC,CAAC,EAAE,CAAC,mBAAmB;YACxB,CAAC,CAAC,4BAA4B,CAAC,CAAC,sBAAsB;QAExD,MAAM,CAAC,MAAM,GAAG,cAAM,OAAA,OAAO,EAAE,EAAT,CAAS,CAAC;QAChC,MAAM,CAAC,OAAO,GAAG;YACf,OAAA,MAAM,CAAC,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAA1D,CAA0D,CAAC;QAE7D,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAgB,YAAY;IAC1B,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;IAChC,MAAM,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC;AAC5C,CAAC;AAED,SAAgB,kBAAkB,CAAC,EAAc;IAC/C,YAAY,EAAE,CAAC;IACf,MAAM,CAAC,SAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC7B,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface VendorConsentResults {
|
|
2
|
+
brandmetrics: boolean;
|
|
3
|
+
linkedIn: boolean;
|
|
4
|
+
purpose1: boolean;
|
|
5
|
+
gdprApplies: boolean;
|
|
6
|
+
usnatApplies: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function initVendorConsentListener(onConsentUpdate: (results: VendorConsentResults) => void): void;
|
|
9
|
+
//# sourceMappingURL=vendorConsent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vendorConsent.d.ts","sourceRoot":"","sources":["../../src/cmp/vendorConsent.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,wBAAgB,yBAAyB,CACvC,eAAe,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,GACvD,IAAI,CAqDN"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.initVendorConsentListener = initVendorConsentListener;
|
|
4
|
+
function initVendorConsentListener(onConsentUpdate) {
|
|
5
|
+
// --- Path 1: Check TCF API First ---
|
|
6
|
+
if (typeof window.__tcfapi === "function") {
|
|
7
|
+
window.__tcfapi("addEventListener", 2, function (tcData, success) {
|
|
8
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
9
|
+
if (!success || !tcData)
|
|
10
|
+
return;
|
|
11
|
+
var isConsentReady = tcData.eventStatus === "tcloaded" ||
|
|
12
|
+
tcData.eventStatus === "useractioncomplete";
|
|
13
|
+
if (isConsentReady) {
|
|
14
|
+
// If GDPR actually applies, process TCF consents (Opt-In model)
|
|
15
|
+
if (tcData.gdprApplies !== false) {
|
|
16
|
+
var results = {
|
|
17
|
+
brandmetrics: ((_b = (_a = tcData.vendor) === null || _a === void 0 ? void 0 : _a.consents) === null || _b === void 0 ? void 0 : _b[422]) === true,
|
|
18
|
+
linkedIn: ((_d = (_c = tcData.vendor) === null || _c === void 0 ? void 0 : _c.consents) === null || _d === void 0 ? void 0 : _d[804]) === true,
|
|
19
|
+
purpose1: ((_f = (_e = tcData.purpose) === null || _e === void 0 ? void 0 : _e.consents) === null || _f === void 0 ? void 0 : _f[1]) === true,
|
|
20
|
+
gdprApplies: true,
|
|
21
|
+
usnatApplies: false,
|
|
22
|
+
};
|
|
23
|
+
onConsentUpdate(results);
|
|
24
|
+
// Clean up TCF listener
|
|
25
|
+
if (typeof tcData.listenerId === "number") {
|
|
26
|
+
(_g = window.__tcfapi) === null || _g === void 0 ? void 0 : _g.call(window, "removeEventListener", 2, function () { }, tcData.listenerId);
|
|
27
|
+
}
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
// --- Path 2: TCF explicitly returned gdprApplies: false -> Fall back to USNat ---
|
|
31
|
+
evaluateUSNatConsent(onConsentUpdate);
|
|
32
|
+
// Clean up TCF listener since GDPR does not apply
|
|
33
|
+
if (typeof tcData.listenerId === "number") {
|
|
34
|
+
(_h = window.__tcfapi) === null || _h === void 0 ? void 0 : _h.call(window, "removeEventListener", 2, function () { }, tcData.listenerId);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
// If __tcfapi doesn't exist at all, try evaluating USNat directly
|
|
41
|
+
evaluateUSNatConsent(onConsentUpdate);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Helper to evaluate USNat / US Privacy consent (Opt-Out model)
|
|
46
|
+
*/
|
|
47
|
+
function evaluateUSNatConsent(onConsentUpdate) {
|
|
48
|
+
var _a, _b;
|
|
49
|
+
// Option A: Preferred Sourcepoint SDK method
|
|
50
|
+
if (typeof ((_b = (_a = window._sp_) === null || _a === void 0 ? void 0 : _a.usnat) === null || _b === void 0 ? void 0 : _b.getUserConsents) === "function") {
|
|
51
|
+
window._sp_.usnat.getUserConsents(function (consents) {
|
|
52
|
+
// US Privacy is OPT-OUT by default.
|
|
53
|
+
// If the user has NOT opted out, consent is considered granted for all vendors/purposes.
|
|
54
|
+
var isOptedOut = (consents === null || consents === void 0 ? void 0 : consents.optedOut) === true ||
|
|
55
|
+
(Array.isArray(consents === null || consents === void 0 ? void 0 : consents.rejectedCategories) &&
|
|
56
|
+
consents.rejectedCategories.length > 0);
|
|
57
|
+
var isConsented = !isOptedOut;
|
|
58
|
+
onConsentUpdate({
|
|
59
|
+
brandmetrics: isConsented,
|
|
60
|
+
linkedIn: isConsented,
|
|
61
|
+
purpose1: isConsented,
|
|
62
|
+
gdprApplies: false,
|
|
63
|
+
usnatApplies: true,
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// Option B: Fallback to GPP standard API
|
|
69
|
+
if (typeof window.__gpp === "function") {
|
|
70
|
+
window.__gpp("getGPPData", function (gppData, success) {
|
|
71
|
+
var _a;
|
|
72
|
+
if (!success || !gppData)
|
|
73
|
+
return;
|
|
74
|
+
var usnat = (_a = gppData.parsedSections) === null || _a === void 0 ? void 0 : _a.usnat;
|
|
75
|
+
// GPP USNat spec: 1 = Opted Out / Yes
|
|
76
|
+
var isOptedOut = (usnat === null || usnat === void 0 ? void 0 : usnat.SharingOptOut) === 1 ||
|
|
77
|
+
(usnat === null || usnat === void 0 ? void 0 : usnat.TargetedAdvertisingOptOut) === 1 ||
|
|
78
|
+
(usnat === null || usnat === void 0 ? void 0 : usnat.SaleOptOut) === 1;
|
|
79
|
+
var isConsented = !isOptedOut;
|
|
80
|
+
onConsentUpdate({
|
|
81
|
+
brandmetrics: isConsented,
|
|
82
|
+
linkedIn: isConsented,
|
|
83
|
+
purpose1: isConsented,
|
|
84
|
+
gdprApplies: false,
|
|
85
|
+
usnatApplies: true,
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=vendorConsent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vendorConsent.js","sourceRoot":"","sources":["../../src/cmp/vendorConsent.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,16 +1,20 @@
|
|
|
1
|
+
import { VendorConsentResults } from "../cmp/vendorConsent";
|
|
1
2
|
export declare class ConsentMonitor {
|
|
2
3
|
private _consent;
|
|
3
4
|
private _devHosts;
|
|
4
5
|
private _isDevEnvironment;
|
|
5
6
|
private _isInitialized;
|
|
6
7
|
private _hostname;
|
|
8
|
+
private _vendorConsents;
|
|
7
9
|
get consent(): boolean;
|
|
8
10
|
get devHosts(): string[];
|
|
9
11
|
get isDevEnvironment(): boolean;
|
|
10
12
|
get isInitialized(): boolean;
|
|
11
13
|
get userHasConsented(): boolean;
|
|
14
|
+
get vendorConsents(): VendorConsentResults;
|
|
12
15
|
getCookieValue: (name: string) => string;
|
|
13
16
|
constructor(hostname?: string, devHosts?: string[] | string);
|
|
17
|
+
private attachVendorConsentListeners;
|
|
14
18
|
private attachCmpListeners;
|
|
15
19
|
private enablePermutive;
|
|
16
20
|
private disablePermutive;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/consentMonitor/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/consentMonitor/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,oBAAoB,EACrB,MAAM,sBAAsB,CAAC;AAwB9B,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAW;IAC5B,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,eAAe,CAMG;IAE1B,IAAW,OAAO,IAAI,OAAO,CAE5B;IACD,IAAW,QAAQ,IAAI,MAAM,EAAE,CAE9B;IACD,IAAW,gBAAgB,IAAI,OAAO,CAErC;IACD,IAAW,aAAa,IAAI,OAAO,CAElC;IACD,IAAW,gBAAgB,IAAI,OAAO,CAErC;IACD,IAAW,cAAc,IAAI,oBAAoB,CAEhD;IAED,cAAc,GAAI,MAAM,MAAM,YACgD;gBAElE,QAAQ,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM;IA4B3D,OAAO,CAAC,4BAA4B;IAapC,OAAO,CAAC,kBAAkB;IAiC1B,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,gBAAgB;IAQxB,iBAAiB,aAcf;IAEF,oBAAoB,aAMlB;CACH;AAED,OAAO,EAAE,cAAc,IAAI,cAAc,EAAE,CAAC"}
|
|
@@ -16,6 +16,7 @@ exports.consentMonitor = exports.ConsentMonitor = void 0;
|
|
|
16
16
|
var cmp_client_1 = require("@financial-times/cmp-client");
|
|
17
17
|
var debug_1 = __importDefault(require("debug"));
|
|
18
18
|
var loadFtCmp_1 = require("../cmp/loadFtCmp");
|
|
19
|
+
var vendorConsent_1 = require("../cmp/vendorConsent");
|
|
19
20
|
var debug = (0, debug_1.default)("@phantomstudios/ft-lib/consentMonitor");
|
|
20
21
|
var DEFAULT_DEV_HOSTS = ["localhost", "phq", ".app", "preview"];
|
|
21
22
|
var CMP_CHOICE_ACCEPT_ALL = 11;
|
|
@@ -26,6 +27,13 @@ var ConsentMonitor = /** @class */ (function () {
|
|
|
26
27
|
this._consent = false;
|
|
27
28
|
this._isDevEnvironment = false;
|
|
28
29
|
this._isInitialized = false;
|
|
30
|
+
this._vendorConsents = {
|
|
31
|
+
brandmetrics: false,
|
|
32
|
+
linkedIn: false,
|
|
33
|
+
purpose1: false,
|
|
34
|
+
gdprApplies: false,
|
|
35
|
+
usnatApplies: false,
|
|
36
|
+
};
|
|
29
37
|
this.getCookieValue = function (name) { var _a; return ((_a = document.cookie.match("(^|;)\\s*" + name + "\\s*=\\s*([^;]+)")) === null || _a === void 0 ? void 0 : _a.pop()) || ""; };
|
|
30
38
|
//check for FTConsent - cookiesOnSite to trigger custom consent_update event for GTM tags (banner updated)
|
|
31
39
|
this.cookieConsentTest = function () {
|
|
@@ -65,16 +73,11 @@ var ConsentMonitor = /** @class */ (function () {
|
|
|
65
73
|
this._isDevEnvironment = this._devHosts.some(function (h) {
|
|
66
74
|
return _this._hostname.includes(h);
|
|
67
75
|
});
|
|
76
|
+
this.attachVendorConsentListeners(); // listen to existing consent data fetch
|
|
77
|
+
this.attachCmpListeners(); // listen to banner interaction
|
|
78
|
+
// load banner
|
|
68
79
|
(0, loadFtCmp_1.loadFtCmpScript)()
|
|
69
80
|
.then(function () {
|
|
70
|
-
_this.attachCmpListeners();
|
|
71
|
-
var propertyConfig = window.location.hostname.endsWith(".ft.com")
|
|
72
|
-
? cmp_client_1.properties["FT_DOTCOM_PROD"]
|
|
73
|
-
: cmp_client_1.properties["FT_DOTCOM_TEST"];
|
|
74
|
-
// initialize CMP
|
|
75
|
-
(0, cmp_client_1.initSourcepointCmp)({ propertyConfig: propertyConfig });
|
|
76
|
-
// use cmp client lib to intercept footer 'Manage Cookies' links (opens privacy modal)
|
|
77
|
-
// Note, function requires very specific link: text = 'Manage Cookies' and href = 'https://ft.com/preferences/manage-cookies'
|
|
78
81
|
(0, cmp_client_1.interceptManageCookiesLinks)();
|
|
79
82
|
_this._isInitialized = true;
|
|
80
83
|
})
|
|
@@ -115,6 +118,25 @@ var ConsentMonitor = /** @class */ (function () {
|
|
|
115
118
|
enumerable: false,
|
|
116
119
|
configurable: true
|
|
117
120
|
});
|
|
121
|
+
Object.defineProperty(ConsentMonitor.prototype, "vendorConsents", {
|
|
122
|
+
get: function () {
|
|
123
|
+
return this._vendorConsents;
|
|
124
|
+
},
|
|
125
|
+
enumerable: false,
|
|
126
|
+
configurable: true
|
|
127
|
+
});
|
|
128
|
+
// Added for required brandmetrics image pixels and linkedin script consent (CMP specific vendor consents integration)
|
|
129
|
+
ConsentMonitor.prototype.attachVendorConsentListeners = function () {
|
|
130
|
+
(0, loadFtCmp_1.enqueueCmpCallback)(function () {
|
|
131
|
+
(0, vendorConsent_1.initVendorConsentListener)(function (vendorConsents) {
|
|
132
|
+
var vendorConsentEvent = new CustomEvent("cmp_vendorConsent", {
|
|
133
|
+
detail: vendorConsents,
|
|
134
|
+
});
|
|
135
|
+
window.dispatchEvent(vendorConsentEvent);
|
|
136
|
+
debug("[CMP Consent lookup Event", vendorConsents);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
};
|
|
118
140
|
ConsentMonitor.prototype.attachCmpListeners = function () {
|
|
119
141
|
var _this = this;
|
|
120
142
|
(0, loadFtCmp_1.enqueueCmpCallback)(function () {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/consentMonitor/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/consentMonitor/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phantomstudios/ft-lib",
|
|
3
3
|
"description": "A collection of Javascript UI & tracking utils for FT sites",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.2-rc10",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
7
7
|
"homepage": "https://github.com/phantomstudios/ft-lib#readme",
|
|
@@ -78,4 +78,4 @@
|
|
|
78
78
|
"@financial-times/o-tracking": "^4.5.1",
|
|
79
79
|
"@financial-times/o-viewport": "^5.1.2"
|
|
80
80
|
}
|
|
81
|
-
}
|
|
81
|
+
}
|
package/src/cmp/loadFtCmp.ts
CHANGED
|
@@ -20,9 +20,12 @@ export function loadFtCmpScript(): Promise<void> {
|
|
|
20
20
|
});
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
export function
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
export function initCmpQueue(): void {
|
|
24
|
+
window._sp_ = window._sp_ || {};
|
|
25
|
+
window._sp_queue = window._sp_queue || [];
|
|
26
|
+
}
|
|
26
27
|
|
|
28
|
+
export function enqueueCmpCallback(cb: () => void): void {
|
|
29
|
+
initCmpQueue();
|
|
27
30
|
window._sp_queue!.push(cb);
|
|
28
31
|
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
export interface VendorConsentResults {
|
|
2
|
+
brandmetrics: boolean;
|
|
3
|
+
linkedIn: boolean;
|
|
4
|
+
purpose1: boolean;
|
|
5
|
+
gdprApplies: boolean;
|
|
6
|
+
usnatApplies: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function initVendorConsentListener(
|
|
10
|
+
onConsentUpdate: (results: VendorConsentResults) => void,
|
|
11
|
+
): void {
|
|
12
|
+
// --- Path 1: Check TCF API First ---
|
|
13
|
+
if (typeof window.__tcfapi === "function") {
|
|
14
|
+
window.__tcfapi("addEventListener", 2, (tcData, success) => {
|
|
15
|
+
if (!success || !tcData) return;
|
|
16
|
+
|
|
17
|
+
const isConsentReady =
|
|
18
|
+
tcData.eventStatus === "tcloaded" ||
|
|
19
|
+
tcData.eventStatus === "useractioncomplete";
|
|
20
|
+
|
|
21
|
+
if (isConsentReady) {
|
|
22
|
+
// If GDPR actually applies, process TCF consents (Opt-In model)
|
|
23
|
+
if (tcData.gdprApplies !== false) {
|
|
24
|
+
const results: VendorConsentResults = {
|
|
25
|
+
brandmetrics: tcData.vendor?.consents?.[422] === true,
|
|
26
|
+
linkedIn: tcData.vendor?.consents?.[804] === true,
|
|
27
|
+
purpose1: tcData.purpose?.consents?.[1] === true,
|
|
28
|
+
gdprApplies: true,
|
|
29
|
+
usnatApplies: false,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
onConsentUpdate(results);
|
|
33
|
+
|
|
34
|
+
// Clean up TCF listener
|
|
35
|
+
if (typeof tcData.listenerId === "number") {
|
|
36
|
+
window.__tcfapi?.(
|
|
37
|
+
"removeEventListener",
|
|
38
|
+
2,
|
|
39
|
+
() => {},
|
|
40
|
+
tcData.listenerId,
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// --- Path 2: TCF explicitly returned gdprApplies: false -> Fall back to USNat ---
|
|
47
|
+
evaluateUSNatConsent(onConsentUpdate);
|
|
48
|
+
|
|
49
|
+
// Clean up TCF listener since GDPR does not apply
|
|
50
|
+
if (typeof tcData.listenerId === "number") {
|
|
51
|
+
window.__tcfapi?.(
|
|
52
|
+
"removeEventListener",
|
|
53
|
+
2,
|
|
54
|
+
() => {},
|
|
55
|
+
tcData.listenerId,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
} else {
|
|
61
|
+
// If __tcfapi doesn't exist at all, try evaluating USNat directly
|
|
62
|
+
evaluateUSNatConsent(onConsentUpdate);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Helper to evaluate USNat / US Privacy consent (Opt-Out model)
|
|
68
|
+
*/
|
|
69
|
+
function evaluateUSNatConsent(
|
|
70
|
+
onConsentUpdate: (results: VendorConsentResults) => void,
|
|
71
|
+
): void {
|
|
72
|
+
// Option A: Preferred Sourcepoint SDK method
|
|
73
|
+
if (typeof window._sp_?.usnat?.getUserConsents === "function") {
|
|
74
|
+
window._sp_.usnat.getUserConsents((consents) => {
|
|
75
|
+
// US Privacy is OPT-OUT by default.
|
|
76
|
+
// If the user has NOT opted out, consent is considered granted for all vendors/purposes.
|
|
77
|
+
const isOptedOut =
|
|
78
|
+
consents?.optedOut === true ||
|
|
79
|
+
(Array.isArray(consents?.rejectedCategories) &&
|
|
80
|
+
consents.rejectedCategories.length > 0);
|
|
81
|
+
|
|
82
|
+
const isConsented = !isOptedOut;
|
|
83
|
+
|
|
84
|
+
onConsentUpdate({
|
|
85
|
+
brandmetrics: isConsented,
|
|
86
|
+
linkedIn: isConsented,
|
|
87
|
+
purpose1: isConsented,
|
|
88
|
+
gdprApplies: false,
|
|
89
|
+
usnatApplies: true,
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Option B: Fallback to GPP standard API
|
|
96
|
+
if (typeof window.__gpp === "function") {
|
|
97
|
+
window.__gpp("getGPPData", (gppData: any, success: boolean) => {
|
|
98
|
+
if (!success || !gppData) return;
|
|
99
|
+
|
|
100
|
+
const usnat = gppData.parsedSections?.usnat;
|
|
101
|
+
|
|
102
|
+
// GPP USNat spec: 1 = Opted Out / Yes
|
|
103
|
+
const isOptedOut =
|
|
104
|
+
usnat?.SharingOptOut === 1 ||
|
|
105
|
+
usnat?.TargetedAdvertisingOptOut === 1 ||
|
|
106
|
+
usnat?.SaleOptOut === 1;
|
|
107
|
+
|
|
108
|
+
const isConsented = !isOptedOut;
|
|
109
|
+
|
|
110
|
+
onConsentUpdate({
|
|
111
|
+
brandmetrics: isConsented,
|
|
112
|
+
linkedIn: isConsented,
|
|
113
|
+
purpose1: isConsented,
|
|
114
|
+
gdprApplies: false,
|
|
115
|
+
usnatApplies: true,
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
initSourcepointCmp,
|
|
3
|
-
interceptManageCookiesLinks,
|
|
4
|
-
properties,
|
|
5
|
-
} from "@financial-times/cmp-client";
|
|
1
|
+
import { interceptManageCookiesLinks } from "@financial-times/cmp-client";
|
|
6
2
|
import Debug from "debug";
|
|
7
3
|
|
|
8
4
|
import { enqueueCmpCallback, loadFtCmpScript } from "../cmp/loadFtCmp";
|
|
5
|
+
import {
|
|
6
|
+
initVendorConsentListener,
|
|
7
|
+
VendorConsentResults,
|
|
8
|
+
} from "../cmp/vendorConsent";
|
|
9
9
|
|
|
10
10
|
const debug = Debug("@phantomstudios/ft-lib/consentMonitor");
|
|
11
11
|
|
|
@@ -35,6 +35,13 @@ export class ConsentMonitor {
|
|
|
35
35
|
private _isDevEnvironment = false;
|
|
36
36
|
private _isInitialized = false;
|
|
37
37
|
private _hostname: string;
|
|
38
|
+
private _vendorConsents = {
|
|
39
|
+
brandmetrics: false,
|
|
40
|
+
linkedIn: false,
|
|
41
|
+
purpose1: false,
|
|
42
|
+
gdprApplies: false,
|
|
43
|
+
usnatApplies: false,
|
|
44
|
+
} as VendorConsentResults;
|
|
38
45
|
|
|
39
46
|
public get consent(): boolean {
|
|
40
47
|
return this._consent;
|
|
@@ -48,10 +55,12 @@ export class ConsentMonitor {
|
|
|
48
55
|
public get isInitialized(): boolean {
|
|
49
56
|
return this._isInitialized;
|
|
50
57
|
}
|
|
51
|
-
|
|
52
58
|
public get userHasConsented(): boolean {
|
|
53
59
|
return this._consent;
|
|
54
60
|
}
|
|
61
|
+
public get vendorConsents(): VendorConsentResults {
|
|
62
|
+
return this._vendorConsents;
|
|
63
|
+
}
|
|
55
64
|
|
|
56
65
|
getCookieValue = (name: string) =>
|
|
57
66
|
document.cookie.match("(^|;)\\s*" + name + "\\s*=\\s*([^;]+)")?.pop() || "";
|
|
@@ -71,24 +80,32 @@ export class ConsentMonitor {
|
|
|
71
80
|
this._hostname.includes(h),
|
|
72
81
|
);
|
|
73
82
|
|
|
83
|
+
this.attachVendorConsentListeners(); // listen to existing consent data fetch
|
|
84
|
+
this.attachCmpListeners(); // listen to banner interaction
|
|
85
|
+
|
|
86
|
+
// load banner
|
|
74
87
|
loadFtCmpScript()
|
|
75
88
|
.then(() => {
|
|
76
|
-
this.attachCmpListeners();
|
|
77
|
-
|
|
78
|
-
const propertyConfig = window.location.hostname.endsWith(".ft.com")
|
|
79
|
-
? properties["FT_DOTCOM_PROD"]
|
|
80
|
-
: properties["FT_DOTCOM_TEST"];
|
|
81
|
-
|
|
82
|
-
// initialize CMP
|
|
83
|
-
initSourcepointCmp({ propertyConfig });
|
|
84
|
-
// use cmp client lib to intercept footer 'Manage Cookies' links (opens privacy modal)
|
|
85
|
-
// Note, function requires very specific link: text = 'Manage Cookies' and href = 'https://ft.com/preferences/manage-cookies'
|
|
86
89
|
interceptManageCookiesLinks();
|
|
87
90
|
this._isInitialized = true;
|
|
88
91
|
})
|
|
89
92
|
.catch((err) => console.error(err));
|
|
90
93
|
}
|
|
91
94
|
|
|
95
|
+
// Added for required brandmetrics image pixels and linkedin script consent (CMP specific vendor consents integration)
|
|
96
|
+
private attachVendorConsentListeners(): void {
|
|
97
|
+
enqueueCmpCallback(() => {
|
|
98
|
+
initVendorConsentListener((vendorConsents: VendorConsentResults) => {
|
|
99
|
+
const vendorConsentEvent = new CustomEvent("cmp_vendorConsent", {
|
|
100
|
+
detail: vendorConsents,
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
window.dispatchEvent(vendorConsentEvent);
|
|
104
|
+
debug("[CMP Consent lookup Event", vendorConsents);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
92
109
|
private attachCmpListeners(): void {
|
|
93
110
|
enqueueCmpCallback(() => {
|
|
94
111
|
const onReady: ConsentReadyHandler = (_l, _u, _t, info) => {
|
package/src/types.d.ts
CHANGED
|
@@ -15,17 +15,44 @@ declare module "@financial-times/cmp-client" {
|
|
|
15
15
|
propertyConfig?: any;
|
|
16
16
|
}): Promise<void>;
|
|
17
17
|
}
|
|
18
|
+
|
|
19
|
+
interface TCFData {
|
|
20
|
+
eventStatus: "tcloaded" | "useractioncomplete" | "cmpuishown";
|
|
21
|
+
listenerId: number;
|
|
22
|
+
purpose?: {
|
|
23
|
+
consents?: Record<number, boolean>;
|
|
24
|
+
};
|
|
25
|
+
vendor?: {
|
|
26
|
+
consents?: Record<number, boolean>;
|
|
27
|
+
};
|
|
28
|
+
gdprApplies?: boolean | undefined;
|
|
29
|
+
}
|
|
18
30
|
interface SourcepointCmpAPI {
|
|
19
31
|
queue?: Array<() => void>;
|
|
20
32
|
addEventListener?: (
|
|
21
33
|
eventName: string,
|
|
22
|
-
|
|
23
34
|
callback: (...args: any[]) => void,
|
|
24
35
|
) => void;
|
|
36
|
+
usnat?: {
|
|
37
|
+
getUserConsents: (callback: (consents: any) => void) => void;
|
|
38
|
+
};
|
|
25
39
|
}
|
|
40
|
+
|
|
26
41
|
interface Window {
|
|
27
42
|
_sp_: SourcepointCmpAPI;
|
|
28
43
|
_sp_queue?: Array<() => void>;
|
|
44
|
+
__tcfapi?: (
|
|
45
|
+
command: string,
|
|
46
|
+
version: number,
|
|
47
|
+
callback: (tcData: TCFData | null, success: boolean) => void,
|
|
48
|
+
parameter?: any,
|
|
49
|
+
) => void;
|
|
50
|
+
__gpp?: (
|
|
51
|
+
command: string,
|
|
52
|
+
callback?: (data: any, success: boolean) => void,
|
|
53
|
+
parameter?: any,
|
|
54
|
+
) => void;
|
|
55
|
+
|
|
29
56
|
dataLayer: any;
|
|
30
57
|
gtag: any;
|
|
31
58
|
permutive: {
|