govuk_publishing_components 37.6.0 → 37.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/stylesheets/govuk_publishing_components/components/_contents-list.scss +1 -1
- data/app/views/govuk_publishing_components/components/_contents_list.html.erb +2 -0
- data/app/views/govuk_publishing_components/components/docs/contents_list.yml +1 -0
- data/lib/govuk_publishing_components/version.rb +1 -1
- data/node_modules/govuk-single-consent/README.md +157 -0
- data/node_modules/govuk-single-consent/dist/singleconsent.cjs.js +419 -0
- data/node_modules/govuk-single-consent/dist/singleconsent.esm.js +417 -0
- data/node_modules/govuk-single-consent/dist/singleconsent.iife.js +431 -0
- data/node_modules/govuk-single-consent/dist/singleconsent.iife.min.js +1 -0
- data/node_modules/govuk-single-consent/package.json +56 -0
- metadata +7 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 057a27088f3e56f3de0b207bf272737059e084e11f7ad5d60c9c64f51b36f36c
|
4
|
+
data.tar.gz: 2e7c53dbecff6dcb761c8b181be7c22a051d1e67738f96d6386cc24b08e4a850
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 853e1a7952502815cc9cf864feedb258266b06f402c37d8622ce3e2a8550b160bfc676e60221b5e6a0332adca201bc7a8b651d3cee2ff451f9ade26c61a74304
|
7
|
+
data.tar.gz: 54df263cbc3fe4b0a4bf2b7f8e3207e5d0292fb6dd79fddfe87cdcea0b844d0c5b4a73527de5ef7d747991e505af18b25228c8644d6c973a5431fb993707a3f7
|
@@ -41,6 +41,7 @@
|
|
41
41
|
<% index_link = 1 unless disable_ga4 %>
|
42
42
|
<% contents.each.with_index(1) do |contents_item, position| %>
|
43
43
|
<li class="<%= cl_helper.list_item_classes(contents_item, false) %>" <%= "aria-current=true" if contents_item[:active] %>>
|
44
|
+
<span aria-hidden="true"></span>
|
44
45
|
<% link_text = format_numbers ? cl_helper.wrap_numbers_with_spans(contents_item[:text]) : contents_item[:text]
|
45
46
|
unless disable_ga4
|
46
47
|
ga4_data[:event_name] = cl_helper.get_ga4_event_name(contents_item[:href]) if contents_item[:href]
|
@@ -64,6 +65,7 @@
|
|
64
65
|
<ol class="gem-c-contents-list__nested-list">
|
65
66
|
<% contents_item[:items].each.with_index(1) do |nested_contents_item, nested_position| %>
|
66
67
|
<li class="<%= cl_helper.list_item_classes(nested_contents_item, true) %>" <%= "aria-current=true" if nested_contents_item[:active] %>>
|
68
|
+
<span aria-hidden="true"></span>
|
67
69
|
<%
|
68
70
|
unless disable_ga4
|
69
71
|
ga4_data[:event_name] = cl_helper.get_ga4_event_name(nested_contents_item[:href]) if nested_contents_item[:href]
|
@@ -18,6 +18,7 @@ accessibility_criteria: |
|
|
18
18
|
- convey the content structure
|
19
19
|
- indicate the current page when contents span different pages, and not link to itself
|
20
20
|
- include an aria-label to contextualise the list
|
21
|
+
- ensure dashes before each list item are hidden from screen readers
|
21
22
|
|
22
23
|
Links with formatted numbers must separate the number and text with a space for correct screen reader pronunciation. This changes pronunciation from "1 dot Item" to "1 Item".
|
23
24
|
shared_accessibility_criteria:
|
@@ -0,0 +1,157 @@
|
|
1
|
+
# Single Consent client
|
2
|
+
|
3
|
+
The Single Consent client is a small Javascript which can be embedded in a
|
4
|
+
website to enable easily sharing a user's consent or rejection of cookies across
|
5
|
+
different websites.
|
6
|
+
|
7
|
+
See the [Single Consent service README](../README.md).
|
8
|
+
|
9
|
+
## Quick start
|
10
|
+
|
11
|
+
See the [CommonJS example](https://github.com/alphagov/consent-api/blob/main/client/examples/commonJS-usage/index.js).
|
12
|
+
|
13
|
+
Contact data-tools-team@digital.cabinet-office.gov.uk to get the URL of the API endpoint.
|
14
|
+
|
15
|
+
The library provides the following static methods for finding out which types of
|
16
|
+
cookies a user has consented to.
|
17
|
+
|
18
|
+
- `hasConsentedToEssential`
|
19
|
+
- `hasConsentedToUsage`
|
20
|
+
- `hasConsentedToCampaigns`
|
21
|
+
- `hasConsentedToSetting`
|
22
|
+
|
23
|
+
The method `GovSingleConsent.getConsents()` provides the current state of the
|
24
|
+
user's consents to all types of cookies.
|
25
|
+
|
26
|
+
### 1. Install with npm
|
27
|
+
|
28
|
+
In order to set first-party cookies, the client Javascript must be served with
|
29
|
+
your application.
|
30
|
+
|
31
|
+
We recommend installing the Single Consent client using
|
32
|
+
[node package manager (npm)](https://www.npmjs.com/).
|
33
|
+
|
34
|
+
```sh
|
35
|
+
npm i govuk-single-consent
|
36
|
+
```
|
37
|
+
|
38
|
+
https://www.npmjs.com/package/govuk-single-consent
|
39
|
+
|
40
|
+
### 2. Including the Javascript client
|
41
|
+
|
42
|
+
The javascript client can be included in different ways. Choose one below.
|
43
|
+
|
44
|
+
#### CommonJS
|
45
|
+
|
46
|
+
See the [example](https://github.com/alphagov/consent-api/blob/main/client/examples/commonJS-usage/index.js).
|
47
|
+
|
48
|
+
#### Typescript
|
49
|
+
|
50
|
+
See the [example](https://github.com/alphagov/consent-api/blob/main/client/examples/typescript-usage/index.ts).
|
51
|
+
|
52
|
+
#### HTML script tag (IIFE)
|
53
|
+
|
54
|
+
The javascript client makes available the object `window.GovSingleConsent` for
|
55
|
+
interacting with the API. It needs to be loaded on any page that could be an
|
56
|
+
entry point to your web application, that allows modifying cookie consent, or
|
57
|
+
provides a link to another domain with which you want to share cookie consent
|
58
|
+
status. It is probably easiest to add the script to a base template used for all
|
59
|
+
pages.
|
60
|
+
|
61
|
+
On the same pages, you need to load your javascript for interacting with the
|
62
|
+
`window.GovSingleConsent` object.
|
63
|
+
|
64
|
+
See the following examples.
|
65
|
+
|
66
|
+
- [Cookie banner script](https://github.com/alphagov/consent-api/blob/main/client/example/cookie-banner.js)
|
67
|
+
- [Cooke page script](https://github.com/alphagov/consent-api/blob/main/client/example/cookies-page.js)
|
68
|
+
|
69
|
+
It is common practice to add Javascript tags just before the end `</body>` tag,
|
70
|
+
eg:
|
71
|
+
|
72
|
+
```html
|
73
|
+
...
|
74
|
+
|
75
|
+
<script src="{path_to_client_js}/singleconsent.js"></script>
|
76
|
+
<script src="{path_to_cookie_banner_script}.js"></script>
|
77
|
+
<script src="{path_to_cookies_page_script}.js"></script>
|
78
|
+
</body>
|
79
|
+
</html>
|
80
|
+
```
|
81
|
+
|
82
|
+
### 3. Passing the base URL to the constructor
|
83
|
+
|
84
|
+
You can either pass an environment string, or a custom base URL.
|
85
|
+
|
86
|
+
If using an environment string, its value should be either `staging` or `production`.
|
87
|
+
|
88
|
+
e.g
|
89
|
+
|
90
|
+
```javascript
|
91
|
+
const dummyCallback = () => {}
|
92
|
+
|
93
|
+
// With an environemnt string to the staging environment
|
94
|
+
new GovSingleConsent(dummyCallback, 'staging')
|
95
|
+
|
96
|
+
// With an environemnt string to the production environment
|
97
|
+
new GovSingleConsent(dummyCallback, 'production')
|
98
|
+
|
99
|
+
// With a custom base URL
|
100
|
+
new GovSingleConsent(dummyCallback, 'http://some-development-url.com')
|
101
|
+
```
|
102
|
+
|
103
|
+
### 4. Share the user's consent to cookies via the API
|
104
|
+
|
105
|
+
When the user interacts with your cookie banner or cookie settings page to
|
106
|
+
consent to or reject cookies you can update the central database by invoking the
|
107
|
+
following function:
|
108
|
+
|
109
|
+
```typescript
|
110
|
+
exampleCookieConsentStatusObject: Consents = {
|
111
|
+
essential: true,
|
112
|
+
settings: false,
|
113
|
+
usage: true,
|
114
|
+
campaigns: false,
|
115
|
+
}
|
116
|
+
|
117
|
+
singleConsentObject.setConsents(exampleCookieConsentStatusObject)
|
118
|
+
```
|
119
|
+
|
120
|
+
## Content Security Policy
|
121
|
+
|
122
|
+
If your website is served with a
|
123
|
+
[`Content-Security-Policy` HTTP header or `<meta>` element](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP), you
|
124
|
+
may need to modify it to allow the client to access the Single Consent service.
|
125
|
+
The value of the header or meta element should contain the following:
|
126
|
+
|
127
|
+
```
|
128
|
+
connect-src 'self' https://consent-api-nw.a.run.app/api/v1/consent [... other site URLs separated by spaces];
|
129
|
+
```
|
130
|
+
|
131
|
+
## What the library does
|
132
|
+
|
133
|
+
The library manages all read/write operations with a cookie that stores the
|
134
|
+
state of a user's consent.
|
135
|
+
|
136
|
+
### Callback
|
137
|
+
|
138
|
+
Websites using the Consent API must provide a callback function. This will be
|
139
|
+
invoked each time the consent has been updated. It will be called with three
|
140
|
+
parameters:
|
141
|
+
|
142
|
+
- `consents` An object describing the new consent state.
|
143
|
+
- `consentsPreferencesSet` Boolean, the cookie banner must be displayed if this
|
144
|
+
value is `false`.
|
145
|
+
- `error` An object describing any error, otherwise `null`. If there is an
|
146
|
+
error, then the `consents` object will say that the consents have been
|
147
|
+
revoked.
|
148
|
+
|
149
|
+
The structure of the consent data object is currently based on the
|
150
|
+
[GOV.UK `cookies_policy` cookie](https://www.gov.uk/help/cookies). If your
|
151
|
+
website cookies do not fall into any of the four categories listed, please
|
152
|
+
contact us.
|
153
|
+
|
154
|
+
## Getting updates
|
155
|
+
|
156
|
+
To be notified when there's a new release, you can watch the
|
157
|
+
[consent-api Github repository](https://github.com/alphagov/consent-api).
|
@@ -0,0 +1,419 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
const DEFAULT_TIMEOUT = 10000;
|
4
|
+
function request(url, options, onSuccess, onError) {
|
5
|
+
try {
|
6
|
+
var req = new XMLHttpRequest();
|
7
|
+
var isTimeout = false;
|
8
|
+
options = options || {};
|
9
|
+
req.onreadystatechange = function () {
|
10
|
+
if (req.readyState === req.DONE) {
|
11
|
+
if (req.status >= 200 && req.status < 400) {
|
12
|
+
let jsonResponse;
|
13
|
+
try {
|
14
|
+
jsonResponse = JSON.parse(req.responseText);
|
15
|
+
onSuccess(jsonResponse);
|
16
|
+
}
|
17
|
+
catch (error) {
|
18
|
+
return onError(error);
|
19
|
+
}
|
20
|
+
}
|
21
|
+
else if (req.status === 0 && req.timeout > 0) {
|
22
|
+
// Possible timeout, waiting for ontimeout event
|
23
|
+
// Timeout will throw a status = 0 request
|
24
|
+
// onreadystatechange preempts ontimeout
|
25
|
+
// And we can't know for sure at this stage if it's a timeout
|
26
|
+
setTimeout(function () {
|
27
|
+
if (isTimeout) {
|
28
|
+
return;
|
29
|
+
}
|
30
|
+
return onError(new Error('Request to ' + url + ' failed with status: ' + req.status));
|
31
|
+
}, 500);
|
32
|
+
}
|
33
|
+
else {
|
34
|
+
return onError(new Error('Request to ' + url + ' failed with status: ' + req.status));
|
35
|
+
}
|
36
|
+
}
|
37
|
+
};
|
38
|
+
req.open(options.method || 'GET', url, true);
|
39
|
+
if (options.timeout) {
|
40
|
+
req.timeout = options.timeout;
|
41
|
+
}
|
42
|
+
else {
|
43
|
+
req.timeout = DEFAULT_TIMEOUT;
|
44
|
+
}
|
45
|
+
req.ontimeout = function () {
|
46
|
+
isTimeout = true;
|
47
|
+
return onError(new Error('Request to ' + url + ' timed out'));
|
48
|
+
};
|
49
|
+
var headers = options.headers || {};
|
50
|
+
for (var name in headers) {
|
51
|
+
req.setRequestHeader(name, headers[name]);
|
52
|
+
}
|
53
|
+
req.send(options.body || null);
|
54
|
+
}
|
55
|
+
catch (error) {
|
56
|
+
return onError(error);
|
57
|
+
}
|
58
|
+
}
|
59
|
+
function addUrlParameter(url, name, value) {
|
60
|
+
url = parseUrl(url);
|
61
|
+
var newParam = name.concat('=', value);
|
62
|
+
var modified = false;
|
63
|
+
findByKey(name, url.params, function (index) {
|
64
|
+
url.params[index] = newParam;
|
65
|
+
modified = true;
|
66
|
+
});
|
67
|
+
if (!modified) {
|
68
|
+
url.params.push(newParam);
|
69
|
+
}
|
70
|
+
return buildUrl(url);
|
71
|
+
}
|
72
|
+
function removeUrlParameter(url, name) {
|
73
|
+
url = parseUrl(url);
|
74
|
+
findByKey(name, url.params, function (index) {
|
75
|
+
url.params.splice(index--, 1);
|
76
|
+
});
|
77
|
+
return buildUrl(url);
|
78
|
+
}
|
79
|
+
function parseUrl(url) {
|
80
|
+
var parts = url.split('?');
|
81
|
+
return {
|
82
|
+
address: parts[0],
|
83
|
+
params: (parts[1] || '').split('&').filter(Boolean),
|
84
|
+
};
|
85
|
+
}
|
86
|
+
function buildUrl(parts) {
|
87
|
+
return [parts.address, parts.params.join('&')].join('?').replace(/\??$/, '');
|
88
|
+
}
|
89
|
+
function findByKey(key, keyvals, callback) {
|
90
|
+
key += '=';
|
91
|
+
for (var index = 0; keyvals.length > index; index++) {
|
92
|
+
if (keyvals[index].trim().slice(0, key.length) === key) {
|
93
|
+
var value = keyvals[index].trim().slice(key.length);
|
94
|
+
if (callback) {
|
95
|
+
callback(index, value);
|
96
|
+
}
|
97
|
+
else {
|
98
|
+
return value;
|
99
|
+
}
|
100
|
+
}
|
101
|
+
}
|
102
|
+
}
|
103
|
+
function isCrossOrigin(link) {
|
104
|
+
return (link.protocol !== window.location.protocol ||
|
105
|
+
link.hostname !== window.location.hostname ||
|
106
|
+
(link.port || '80') !== (window.location.port || '80'));
|
107
|
+
}
|
108
|
+
function getOriginFromLink(link) {
|
109
|
+
var origin = link.protocol.concat('//', link.hostname);
|
110
|
+
if (link.port && link.port !== '80' && link.port !== '443') {
|
111
|
+
origin = origin.concat(':', link.port);
|
112
|
+
}
|
113
|
+
return origin;
|
114
|
+
}
|
115
|
+
function isBrowser() {
|
116
|
+
return typeof module === 'undefined';
|
117
|
+
}
|
118
|
+
function setCookie({ name, value, lifetime }) {
|
119
|
+
// const encodedValue = encodeURIComponent(value)
|
120
|
+
const encodedValue = value;
|
121
|
+
document.cookie = name
|
122
|
+
.concat('=', encodedValue)
|
123
|
+
.concat('; path=/', '; max-age='.concat(lifetime.toString()), document.location.protocol === 'https:' ? '; Secure' : '');
|
124
|
+
}
|
125
|
+
function getCookie(name, defaultValue) {
|
126
|
+
name += '=';
|
127
|
+
const cookies = document.cookie.split(';');
|
128
|
+
let cookie = null;
|
129
|
+
for (let i = 0; i < cookies.length; i++) {
|
130
|
+
let currentCookie = cookies[i].trim();
|
131
|
+
if (currentCookie.indexOf(name) === 0) {
|
132
|
+
cookie = currentCookie;
|
133
|
+
break;
|
134
|
+
}
|
135
|
+
}
|
136
|
+
if (cookie) {
|
137
|
+
return decodeURIComponent(cookie.trim().slice(name.length));
|
138
|
+
}
|
139
|
+
return defaultValue || null;
|
140
|
+
}
|
141
|
+
function validateConsentObject(response) {
|
142
|
+
try {
|
143
|
+
if (typeof response !== 'object' || response === null) {
|
144
|
+
return false;
|
145
|
+
}
|
146
|
+
var expectedKeys = ['essential', 'settings', 'usage', 'campaigns'];
|
147
|
+
var allKeysPresent = true;
|
148
|
+
var responseKeysCount = 0;
|
149
|
+
for (var i = 0; i < expectedKeys.length; i++) {
|
150
|
+
if (!(expectedKeys[i] in response)) {
|
151
|
+
allKeysPresent = false;
|
152
|
+
break;
|
153
|
+
}
|
154
|
+
}
|
155
|
+
var allValuesBoolean = true;
|
156
|
+
for (var key in response) {
|
157
|
+
if (response.hasOwnProperty(key)) {
|
158
|
+
responseKeysCount++;
|
159
|
+
if (typeof response[key] !== 'boolean') {
|
160
|
+
allValuesBoolean = false;
|
161
|
+
break;
|
162
|
+
}
|
163
|
+
}
|
164
|
+
}
|
165
|
+
var correctNumberOfKeys = responseKeysCount === expectedKeys.length;
|
166
|
+
}
|
167
|
+
catch (err) {
|
168
|
+
return false;
|
169
|
+
}
|
170
|
+
return allKeysPresent && allValuesBoolean && correctNumberOfKeys;
|
171
|
+
}
|
172
|
+
|
173
|
+
const COOKIE_DAYS = 365;
|
174
|
+
class GovConsentConfig {
|
175
|
+
constructor(baseUrl) {
|
176
|
+
this.uidFromCookie = findByKey(GovConsentConfig.UID_KEY, document.cookie.split(';'));
|
177
|
+
this.uidFromUrl = findByKey(GovConsentConfig.UID_KEY, parseUrl(location.href).params);
|
178
|
+
this.baseUrl = baseUrl;
|
179
|
+
}
|
180
|
+
}
|
181
|
+
GovConsentConfig.UID_KEY = 'gov_singleconsent_uid';
|
182
|
+
GovConsentConfig.CONSENTS_COOKIE_NAME = 'cookies_policy';
|
183
|
+
GovConsentConfig.PREFERENCES_SET_COOKIE_NAME = 'cookies_preferences_set';
|
184
|
+
GovConsentConfig.COOKIE_LIFETIME = COOKIE_DAYS * 24 * 60 * 60;
|
185
|
+
|
186
|
+
class ApiV1 {
|
187
|
+
constructor(baseUrl) {
|
188
|
+
this.version = 'v1';
|
189
|
+
this.baseUrl = baseUrl;
|
190
|
+
}
|
191
|
+
buildUrl(endpoint, pathParam) {
|
192
|
+
let url = `${this.baseUrl}/api/${this.version}${endpoint}`;
|
193
|
+
if (pathParam) {
|
194
|
+
url += `/${pathParam}`;
|
195
|
+
}
|
196
|
+
return url;
|
197
|
+
}
|
198
|
+
origins() {
|
199
|
+
return this.buildUrl(ApiV1.Routes.origins);
|
200
|
+
}
|
201
|
+
consents(id) {
|
202
|
+
return this.buildUrl(ApiV1.Routes.consents, id || '');
|
203
|
+
}
|
204
|
+
}
|
205
|
+
ApiV1.Routes = {
|
206
|
+
origins: '/origins',
|
207
|
+
consents: '/consent',
|
208
|
+
};
|
209
|
+
|
210
|
+
class GovSingleConsent {
|
211
|
+
constructor(consentsUpdateCallback, baseUrlOrEnv) {
|
212
|
+
/**
|
213
|
+
Initialises _GovConsent object by performing the following:
|
214
|
+
1. Removes 'uid' from URL.
|
215
|
+
2. Sets 'uid' attribute from cookie or URL.
|
216
|
+
3. Fetches consent status from API if 'uid' exists.
|
217
|
+
4. Notifies event listeners with API response.
|
218
|
+
|
219
|
+
@arg baseUrl: string - the domain of where the single consent API is. Required.
|
220
|
+
@arg consentsUpdateCallback: function(consents, consentsPreferencesSet, error) - callback when the consents are updated
|
221
|
+
"consents": this is the consents object. It has the following properties: "essential", "usage", "campaigns", "settings". Each property is a boolean.
|
222
|
+
"consentsPreferencesSet": true if the consents have been set for this user and this domain. Typically, only display the cookie banner if this is true.
|
223
|
+
"error": if an error occurred, this is the error object. Otherwise, this is null.
|
224
|
+
*/
|
225
|
+
this.cachedConsentsCookie = null;
|
226
|
+
this.validateConstructorArguments(baseUrlOrEnv, consentsUpdateCallback);
|
227
|
+
const baseUrl = this.resolveBaseUrl(baseUrlOrEnv);
|
228
|
+
this._consentsUpdateCallback = consentsUpdateCallback;
|
229
|
+
this.config = new GovConsentConfig(baseUrl);
|
230
|
+
this.urls = new ApiV1(this.config.baseUrl);
|
231
|
+
window.cachedConsentsCookie = null;
|
232
|
+
this.hideUIDParameter();
|
233
|
+
this.initialiseUIDandConsents();
|
234
|
+
}
|
235
|
+
validateConstructorArguments(baseUrlOrEnv, consentsUpdateCallback) {
|
236
|
+
if (!baseUrlOrEnv) {
|
237
|
+
throw new Error('Argument baseUrl is required');
|
238
|
+
}
|
239
|
+
if (typeof baseUrlOrEnv !== 'string') {
|
240
|
+
throw new Error('Argument baseUrl must be a string');
|
241
|
+
}
|
242
|
+
if (!consentsUpdateCallback) {
|
243
|
+
throw new Error('Argument consentsUpdateCallback is required');
|
244
|
+
}
|
245
|
+
if (typeof consentsUpdateCallback !== 'function') {
|
246
|
+
throw new Error('Argument consentsUpdateCallback must be a function');
|
247
|
+
}
|
248
|
+
}
|
249
|
+
resolveBaseUrl(baseUrlOrEnv) {
|
250
|
+
if (baseUrlOrEnv === 'staging') {
|
251
|
+
return 'https://gds-single-consent-staging.app';
|
252
|
+
}
|
253
|
+
else if (baseUrlOrEnv === 'production') {
|
254
|
+
return 'https://gds-single-consent.app';
|
255
|
+
}
|
256
|
+
// If not "staging" or "production", assume it's a custom URL
|
257
|
+
return baseUrlOrEnv;
|
258
|
+
}
|
259
|
+
initialiseUIDandConsents() {
|
260
|
+
const currentUID = this.getCurrentUID();
|
261
|
+
if (this.isNewUID(currentUID)) {
|
262
|
+
this.handleNewUID(currentUID);
|
263
|
+
}
|
264
|
+
if (this.uid) {
|
265
|
+
this.fetchAndUpdateConsents();
|
266
|
+
}
|
267
|
+
else {
|
268
|
+
this._consentsUpdateCallback(null, false, null);
|
269
|
+
}
|
270
|
+
}
|
271
|
+
handleNewUID(newUID) {
|
272
|
+
this.uid = newUID;
|
273
|
+
this.updateLinksEventHandlers(newUID);
|
274
|
+
this.setUIDCookie(newUID);
|
275
|
+
}
|
276
|
+
isNewUID(currentUID) {
|
277
|
+
return currentUID && currentUID !== this.uid;
|
278
|
+
}
|
279
|
+
fetchAndUpdateConsents() {
|
280
|
+
const consentsUrl = this.urls.consents(this.uid);
|
281
|
+
request(consentsUrl, { timeout: 1000 }, (jsonResponse) => {
|
282
|
+
if (!validateConsentObject(jsonResponse.status)) {
|
283
|
+
const error = new Error('Invalid consents object returned from the API: ' + JSON.stringify(jsonResponse));
|
284
|
+
return this.defaultToRejectAllConsents(error);
|
285
|
+
}
|
286
|
+
const consents = jsonResponse.status;
|
287
|
+
this.updateBrowserConsents(consents);
|
288
|
+
this._consentsUpdateCallback(consents, GovSingleConsent.isConsentPreferencesSet(), null);
|
289
|
+
}, (error) => this.defaultToRejectAllConsents(error));
|
290
|
+
}
|
291
|
+
getCurrentUID() {
|
292
|
+
// Get the current uid from URL or from the cookie if it exists
|
293
|
+
return this.config.uidFromUrl || this.config.uidFromCookie;
|
294
|
+
}
|
295
|
+
setConsents(consents) {
|
296
|
+
if (!consents) {
|
297
|
+
throw new Error('consents is required in GovSingleConsent.setConsents()');
|
298
|
+
}
|
299
|
+
const successCallback = (response) => {
|
300
|
+
if (!response.uid) {
|
301
|
+
throw new Error('No UID returned from the API');
|
302
|
+
}
|
303
|
+
if (this.isNewUID(response.uid)) {
|
304
|
+
this.handleNewUID(response.uid);
|
305
|
+
}
|
306
|
+
this.updateBrowserConsents(consents);
|
307
|
+
this._consentsUpdateCallback(consents, GovSingleConsent.isConsentPreferencesSet(), null);
|
308
|
+
};
|
309
|
+
const url = this.urls.consents(this.uid);
|
310
|
+
request(url, {
|
311
|
+
method: 'POST',
|
312
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
313
|
+
body: 'status='.concat(JSON.stringify(consents)),
|
314
|
+
}, successCallback, (error) => this.defaultToRejectAllConsents(error));
|
315
|
+
}
|
316
|
+
defaultToRejectAllConsents(error) {
|
317
|
+
this.updateBrowserConsents(GovSingleConsent.REJECT_ALL);
|
318
|
+
this._consentsUpdateCallback(GovSingleConsent.REJECT_ALL, GovSingleConsent.isConsentPreferencesSet(), error);
|
319
|
+
}
|
320
|
+
static getConsents() {
|
321
|
+
if (window.cachedConsentsCookie) {
|
322
|
+
return window.cachedConsentsCookie;
|
323
|
+
}
|
324
|
+
const cookieValue = getCookie(GovConsentConfig.CONSENTS_COOKIE_NAME, null);
|
325
|
+
if (cookieValue) {
|
326
|
+
return JSON.parse(cookieValue);
|
327
|
+
}
|
328
|
+
return null;
|
329
|
+
}
|
330
|
+
static hasConsentedToEssential() {
|
331
|
+
const consents = GovSingleConsent.getConsents();
|
332
|
+
return consents === null || consents === void 0 ? void 0 : consents.essential;
|
333
|
+
}
|
334
|
+
static hasConsentedToUsage() {
|
335
|
+
const consents = GovSingleConsent.getConsents();
|
336
|
+
return consents === null || consents === void 0 ? void 0 : consents.usage;
|
337
|
+
}
|
338
|
+
static hasConsentedToCampaigns() {
|
339
|
+
const consents = GovSingleConsent.getConsents();
|
340
|
+
return consents === null || consents === void 0 ? void 0 : consents.campaigns;
|
341
|
+
}
|
342
|
+
static hasConsentedToSettings() {
|
343
|
+
const consents = GovSingleConsent.getConsents();
|
344
|
+
return consents === null || consents === void 0 ? void 0 : consents.settings;
|
345
|
+
}
|
346
|
+
static isConsentPreferencesSet() {
|
347
|
+
const value = getCookie(GovConsentConfig.PREFERENCES_SET_COOKIE_NAME, null);
|
348
|
+
return value === 'true';
|
349
|
+
}
|
350
|
+
updateLinksEventHandlers(currentUID) {
|
351
|
+
request(this.urls.origins(), {},
|
352
|
+
// Update links with UID
|
353
|
+
(origins) => this.addUIDtoCrossOriginLinks(origins, currentUID), (error) => {
|
354
|
+
throw error;
|
355
|
+
});
|
356
|
+
}
|
357
|
+
addUIDtoCrossOriginLinks(origins, uid) {
|
358
|
+
/**
|
359
|
+
* Adds uid URL parameter to consent sharing links.
|
360
|
+
* Only links with known origins are updated.
|
361
|
+
*/
|
362
|
+
const links = document.querySelectorAll('a[href]');
|
363
|
+
Array.prototype.forEach.call(links, (link) => {
|
364
|
+
if (isCrossOrigin(link) &&
|
365
|
+
origins.indexOf(getOriginFromLink(link)) >= 0) {
|
366
|
+
link.addEventListener('click', (event) => {
|
367
|
+
event.target.href = addUrlParameter(event.target.href, GovConsentConfig.UID_KEY, uid);
|
368
|
+
});
|
369
|
+
}
|
370
|
+
});
|
371
|
+
}
|
372
|
+
setUIDCookie(uid) {
|
373
|
+
setCookie({
|
374
|
+
name: GovConsentConfig.UID_KEY,
|
375
|
+
value: uid,
|
376
|
+
lifetime: GovConsentConfig.COOKIE_LIFETIME,
|
377
|
+
});
|
378
|
+
}
|
379
|
+
updateBrowserConsents(consents) {
|
380
|
+
this.setConsentsCookie(consents);
|
381
|
+
this.setPreferencesSetCookie(true);
|
382
|
+
window.cachedConsentsCookie = consents;
|
383
|
+
}
|
384
|
+
setConsentsCookie(consents) {
|
385
|
+
setCookie({
|
386
|
+
name: GovConsentConfig.CONSENTS_COOKIE_NAME,
|
387
|
+
value: JSON.stringify(consents),
|
388
|
+
lifetime: GovConsentConfig.COOKIE_LIFETIME,
|
389
|
+
});
|
390
|
+
}
|
391
|
+
setPreferencesSetCookie(value) {
|
392
|
+
setCookie({
|
393
|
+
name: GovConsentConfig.PREFERENCES_SET_COOKIE_NAME,
|
394
|
+
value: value.toString(),
|
395
|
+
lifetime: GovConsentConfig.COOKIE_LIFETIME,
|
396
|
+
});
|
397
|
+
}
|
398
|
+
hideUIDParameter() {
|
399
|
+
history.replaceState(null, null, removeUrlParameter(location.href, GovConsentConfig.UID_KEY));
|
400
|
+
}
|
401
|
+
}
|
402
|
+
GovSingleConsent.ACCEPT_ALL = {
|
403
|
+
essential: true,
|
404
|
+
usage: true,
|
405
|
+
campaigns: true,
|
406
|
+
settings: true,
|
407
|
+
};
|
408
|
+
GovSingleConsent.REJECT_ALL = {
|
409
|
+
essential: true,
|
410
|
+
usage: false,
|
411
|
+
campaigns: false,
|
412
|
+
settings: false,
|
413
|
+
};
|
414
|
+
|
415
|
+
if (isBrowser()) {
|
416
|
+
window.GovSingleConsent = GovSingleConsent;
|
417
|
+
}
|
418
|
+
|
419
|
+
exports.GovSingleConsent = GovSingleConsent;
|