@ons/design-system 74.0.0-next.14 → 74.0.0-next.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/README.md +1 -1
  2. package/components/card/example-card-set-with-headline-figures.njk +4 -4
  3. package/components/chart/_chart.scss +0 -12
  4. package/components/chart/_macro.njk +62 -80
  5. package/components/chart/_macro.spec.js +0 -240
  6. package/components/chart/bar-chart.js +6 -1
  7. package/components/cookies-banner/_macro.njk +1 -1
  8. package/components/cookies-banner/_macro.spec.js +15 -3
  9. package/components/header/_macro.njk +4 -0
  10. package/components/message/_message.scss +3 -3
  11. package/components/summary/_macro.njk +3 -2
  12. package/components/summary/_summary.scss +6 -1
  13. package/components/table-of-contents/example-table-of-contents-sticky-full-page-ordered.njk +104 -106
  14. package/components/table-of-contents/example-table-of-contents-sticky-full-page.njk +103 -105
  15. package/components/table-of-contents/example-table-of-contents-sticky.njk +1 -1
  16. package/css/main.css +1 -1
  17. package/js/chart.js +0 -2
  18. package/js/cookies-functions.js +31 -42
  19. package/js/cookies-functions.spec.js +90 -46
  20. package/layout/_template.njk +1 -1
  21. package/package.json +2 -3
  22. package/scripts/chart.es5.js +1 -3
  23. package/scripts/chart.js +1 -3
  24. package/scripts/main.es5.js +1 -1
  25. package/scripts/main.js +1 -1
  26. package/scss/objects/_container.scss +21 -4
  27. package/scss/utilities/_grid.scss +10 -25
  28. package/scss/vars/_forms.scss +0 -11
  29. package/scss/vars/_grid.scss +22 -3
  30. package/scss/vars/_utilities.scss +1 -1
  31. package/components/chart/chart-iframe-resize.dom.js +0 -8
  32. package/components/chart/chart-iframe-resize.js +0 -16
  33. package/components/chart/example-iframe-chart.njk +0 -36
package/js/chart.js CHANGED
@@ -1,4 +1,2 @@
1
1
  import '../components/chart/chart';
2
2
  import '../components/chart/chart.dom';
3
- import '../components/chart/chart-iframe-resize';
4
- import '../components/chart/chart-iframe-resize.dom';
@@ -74,7 +74,6 @@ export function getConsentCookie() {
74
74
  }
75
75
 
76
76
  export function setConsentCookie(options) {
77
- const domain = getDomain(document.domain);
78
77
  let cookieConsent = getConsentCookie();
79
78
  if (!cookieConsent) {
80
79
  cookieConsent = JSON.parse(JSON.stringify(DEFAULT_COOKIE_CONSENT).replace(/'/g, '"'));
@@ -85,10 +84,6 @@ export function setConsentCookie(options) {
85
84
  for (let cookies in COOKIE_CATEGORIES) {
86
85
  if (COOKIE_CATEGORIES[cookies] === cookieType) {
87
86
  cookie(cookies, null);
88
- if (cookie(cookies)) {
89
- const cookieString = cookies + '=; expires=' + new Date() + '; domain=' + domain + '; path=/';
90
- document.cookie = cookieString;
91
- }
92
87
  }
93
88
  }
94
89
  }
@@ -127,27 +122,25 @@ export function checkConsentCookie(cookieName, cookieValue) {
127
122
  }
128
123
 
129
124
  export function setCookie(name, value, options) {
130
- const domain = getDomain(document.domain);
131
- let setDomain = '';
125
+ if (typeof options === 'undefined') {
126
+ options = {};
127
+ }
132
128
 
133
- if (domain.indexOf('localhost') === -1) {
134
- setDomain = '; domain=' + domain;
129
+ if (options.days && options.days < 0) {
130
+ deleteCookie(name);
131
+ return;
135
132
  }
136
133
 
137
134
  if (checkConsentCookie(name, value)) {
138
- if (typeof options === 'undefined') {
139
- options = {};
140
- }
135
+ const secure = getSecureAttribute();
141
136
 
142
- let cookieString = name + '=' + value + setDomain + '; path=/';
137
+ let cookieString = name + '=' + value + getCookieDomainAttribute() + '; path=/';
143
138
  if (options.days) {
144
139
  const date = new Date();
145
140
  date.setTime(date.getTime() + options.days * 24 * 60 * 60 * 1000);
146
141
  cookieString = cookieString + '; expires=' + date.toGMTString();
147
142
  }
148
- if (document.location.protocol === 'https:') {
149
- cookieString = cookieString + '; Secure';
150
- }
143
+ cookieString = cookieString + secure;
151
144
  document.cookie = cookieString;
152
145
  }
153
146
  }
@@ -167,38 +160,34 @@ export function getCookie(name) {
167
160
  return null;
168
161
  }
169
162
 
170
- function getCookieDomainPolicy() {
163
+ function getCookieDomain() {
171
164
  const banner = document.querySelector('.ons-cookies-banner');
172
- const policy = banner ? banner.getAttribute('data-ons-cookie-domain-policy') : null;
173
-
174
- // plan: add 'exact-host' policy in future and retire 'legacy' and 'day1'
175
- switch (policy) {
176
- case 'legacy':
177
- case 'day1':
178
- return policy;
179
- default:
180
- return 'legacy';
165
+ const configuredDomain = banner ? banner.getAttribute('data-ons-cookie-domain') : null;
166
+
167
+ if (configuredDomain !== null) {
168
+ return configuredDomain;
169
+ } else {
170
+ return document.location.hostname;
181
171
  }
182
172
  }
183
173
 
184
- export function getDomain(domain, cookieHandler = document) {
185
- const cookieDomainPolicy = getCookieDomainPolicy();
174
+ function getCookieDomainAttribute() {
175
+ const domain = getCookieDomain();
186
176
 
187
- if (cookieDomainPolicy === 'legacy' && domain.startsWith('www.')) {
188
- domain = domain.substring(4);
177
+ if (!domain) {
178
+ return '';
189
179
  }
190
180
 
191
- let i = 0,
192
- domainName = domain,
193
- p = domainName.split('.'),
194
- s = '_gd' + new Date().getTime();
195
- while (i < p.length - 1 && cookieHandler.cookie.indexOf(s + '=' + s) == -1) {
196
- // Loop until we find a valid cookie set at the domain or until we've checked all possible domains
197
- domainName = p.slice(i, p.length).join('.');
198
- cookieHandler.cookie = s + '=' + s + ';domain=' + domainName + ';';
181
+ return '; domain=' + domain;
182
+ }
199
183
 
200
- i++;
201
- }
202
- cookieHandler.cookie = s + '=;expires=Thu, 01 Jan 1970 00:00:01 GMT;domain=' + domainName + ';';
203
- return domainName;
184
+ function deleteCookie(name) {
185
+ const expires = new Date(0).toGMTString();
186
+ const secure = getSecureAttribute();
187
+
188
+ document.cookie = name + '=' + getCookieDomainAttribute() + '; path=/; expires=' + expires + secure;
189
+ }
190
+
191
+ function getSecureAttribute() {
192
+ return document.location.protocol === 'https:' ? '; Secure' : '';
204
193
  }
@@ -1,65 +1,109 @@
1
- /** @jest-environment jsdom */
1
+ /**
2
+ * @jest-environment jsdom
3
+ * @jest-environment-options {"url":"https://www.ons.gov.uk/"}
4
+ */
2
5
 
3
- import { getDomain } from './cookies-functions';
6
+ import { setConsentCookie, setCookie } from './cookies-functions';
7
+
8
+ let cookieAssignments = [];
4
9
  let mockCookieStore = {};
5
10
 
6
- // Mocking document.cookie which is used for setting domain name in `getDomain()`
7
- export const setMockcookie = {
8
- get cookie() {
9
- return Object.entries(mockCookieStore)
10
- .map(([key, value]) => `${key}=${value}`)
11
- .join('; ');
12
- },
13
- set cookie(value) {
14
- const domainMatch = value.match(/domain=([^;]+)/i);
15
- const domain = domainMatch?.[1]?.trim();
16
-
17
- // Simulate failure to set cookie on this domain
18
- if (domain === 'new-website.ons.gov.uk') return;
19
-
20
- const [key, val] = value.split('=');
21
- mockCookieStore[key] = val.split(';')[0];
22
- },
23
- };
24
-
25
- describe('script: getDomain()', () => {
11
+ function setCookieDomain(domain) {
12
+ const banner = document.createElement('div');
13
+ banner.className = 'ons-cookies-banner';
14
+ banner.setAttribute('data-ons-cookie-domain', domain);
15
+ document.body.appendChild(banner);
16
+ }
17
+
18
+ function getLastCookieAssignment() {
19
+ return cookieAssignments[cookieAssignments.length - 1];
20
+ }
21
+
22
+ describe('script: cookies-functions', () => {
26
23
  beforeEach(() => {
27
- mockCookieStore = {}; // clear the cookie between tests
24
+ cookieAssignments = [];
25
+ mockCookieStore = {};
28
26
  document.body.innerHTML = '';
27
+
28
+ Object.defineProperty(document, 'cookie', {
29
+ get() {
30
+ return Object.entries(mockCookieStore)
31
+ .map(([key, value]) => `${key}=${value}`)
32
+ .join('; ');
33
+ },
34
+ set(value) {
35
+ cookieAssignments.push(value);
36
+
37
+ const [key, val] = value.split('=');
38
+ if (value.includes('expires=Thu, 01 Jan 1970')) {
39
+ delete mockCookieStore[key];
40
+ } else {
41
+ mockCookieStore[key] = val.split(';')[0];
42
+ }
43
+ },
44
+ configurable: true,
45
+ });
29
46
  });
30
47
 
31
- test('should return service-manual.ons.gov.uk as the domain name when cookies can be set at the full subdomain', () => {
32
- const result = getDomain('service-manual.ons.gov.uk', setMockcookie);
33
- expect(result).toBe('service-manual.ons.gov.uk');
48
+ test('sets a domain cookie using the current hostname by default', () => {
49
+ setCookie('ons_cookie_policy', 'test-value', { days: 365 });
50
+
51
+ expect(cookieAssignments).toHaveLength(1);
52
+ expect(getLastCookieAssignment()).toContain('ons_cookie_policy=test-value; domain=www.ons.gov.uk; path=/');
34
53
  });
35
54
 
36
- test('should remove `www` from the domain name www.ons.gov.uk', () => {
37
- const result = getDomain('www.ons.gov.uk', setMockcookie);
38
- expect(result).toBe('ons.gov.uk');
55
+ test('does not expire other scopes before setting banner state', () => {
56
+ setCookie('ons_cookie_message_displayed', 'true', { days: 365 });
57
+
58
+ expect(cookieAssignments).toHaveLength(1);
59
+ expect(getLastCookieAssignment()).toContain('ons_cookie_message_displayed=true; domain=www.ons.gov.uk; path=/');
39
60
  });
40
61
 
41
- test('removes `www` when cookieDomainPolicy is `legacy`', () => {
42
- const banner = document.createElement('div');
43
- banner.className = 'ons-cookies-banner';
44
- banner.setAttribute('data-ons-cookie-domain-policy', 'legacy');
45
- document.body.appendChild(banner);
62
+ test('does not expire other scopes before setting other cookie categories', () => {
63
+ setCookie('_ga', 'test-value', { days: 365 });
46
64
 
47
- const result = getDomain('www.ons.gov.uk', setMockcookie);
48
- expect(result).toBe('ons.gov.uk');
65
+ expect(cookieAssignments).toHaveLength(1);
66
+ expect(getLastCookieAssignment()).toContain('_ga=test-value; domain=www.ons.gov.uk; path=/');
49
67
  });
50
68
 
51
- test('does not remove `www` when cookieDomainPolicy is `day1`', () => {
52
- const banner = document.createElement('div');
53
- banner.className = 'ons-cookies-banner';
54
- banner.setAttribute('data-ons-cookie-domain-policy', 'day1');
55
- document.body.appendChild(banner);
69
+ test('sets domain cookies when `domain` is provided', () => {
70
+ setCookieDomain('census.gov.uk');
71
+
72
+ setCookie('ons_cookie_policy', 'test-value', { days: 365 });
56
73
 
57
- const result = getDomain('www.ons.gov.uk', setMockcookie);
58
- expect(result).toBe('www.ons.gov.uk');
74
+ expect(getLastCookieAssignment()).toContain('ons_cookie_policy=test-value; domain=census.gov.uk; path=/');
59
75
  });
60
76
 
61
- test('returns `ons.gov.uk` as the domain name when cookies can not be set at subdomain `new-website.ons.gov.uk`', () => {
62
- const result = getDomain('new-website.ons.gov.uk', setMockcookie);
63
- expect(result).toBe('ons.gov.uk');
77
+ test('sets host-only cookies when `domain` is explicitly false', () => {
78
+ setCookieDomain('');
79
+
80
+ setCookie('ons_cookie_policy', 'test-value', { days: 365 });
81
+
82
+ expect(cookieAssignments).toHaveLength(1);
83
+ expect(getLastCookieAssignment()).toContain('ons_cookie_policy=test-value; path=/');
84
+ expect(getLastCookieAssignment()).not.toMatch(/; domain=/i);
85
+ });
86
+
87
+ test('deletes only the default domain scope', () => {
88
+ setCookie('_ga', null, { days: -1 });
89
+
90
+ expect(cookieAssignments).toEqual(['_ga=; domain=www.ons.gov.uk; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; Secure']);
91
+ });
92
+
93
+ test('deletes only the configured domain scope', () => {
94
+ setCookieDomain('census.gov.uk');
95
+
96
+ setCookie('_ga', null, { days: -1 });
97
+
98
+ expect(cookieAssignments).toEqual(['_ga=; domain=census.gov.uk; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; Secure']);
99
+ });
100
+
101
+ test('deletes category cookies when consent is rejected', () => {
102
+ mockCookieStore.ons_cookie_policy = "{'essential':true,'settings':true,'usage':true,'campaigns':true}";
103
+ mockCookieStore._ga = 'test-value';
104
+
105
+ setConsentCookie({ usage: false });
106
+
107
+ expect(cookieAssignments).toContain('_ga=; domain=www.ons.gov.uk; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; Secure');
64
108
  });
65
109
  });
@@ -263,7 +263,7 @@
263
263
  (function() {
264
264
  var s = [ '{{ assetsUrl }}/scripts/main.js' ],
265
265
  c = document.createElement('script');
266
- var hasCharts = !!document.querySelector('[data-highcharts-base-chart], .ons-chart__iframe-wrapper iframe');
266
+ var hasCharts = !!document.querySelector('[data-highcharts-base-chart]');
267
267
 
268
268
  if (hasCharts) {
269
269
  s.push('{{ assetsUrl }}/scripts/chart.js');
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ons/design-system",
3
3
  "description": "ONS Design System built CSS, JS, and Nunjucks templates",
4
- "version": "74.0.0-next.14",
4
+ "version": "74.0.0-next.16",
5
5
  "main": "index.js",
6
6
  "license": "MIT",
7
7
  "author": {
@@ -144,8 +144,7 @@
144
144
  "access": "public"
145
145
  },
146
146
  "dependencies": {
147
- "highcharts": "12.1.2",
148
- "pym.js": "1.3.2"
147
+ "highcharts": "12.1.2"
149
148
  },
150
149
  "resolutions": {
151
150
  "backstopjs/puppeteer": "25.11.0",