bv-ui-core 0.1.1

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 (122) hide show
  1. package/.eslintrc +40 -0
  2. package/.travis.yml +5 -0
  3. package/CONTRIBUTING.md +98 -0
  4. package/LICENSE.md +13 -0
  5. package/OWNERS +2 -0
  6. package/README.md +63 -0
  7. package/catalog-info.yaml +30 -0
  8. package/karma.conf.js +130 -0
  9. package/lib/README.md +61 -0
  10. package/lib/api/.babelrc +3 -0
  11. package/lib/api/.eslintrc +9 -0
  12. package/lib/api/README.md +134 -0
  13. package/lib/api/index.js +15 -0
  14. package/lib/api/statistics.js +148 -0
  15. package/lib/application/README.md +96 -0
  16. package/lib/application/index.js +171 -0
  17. package/lib/body/README.md +13 -0
  18. package/lib/body/index.js +19 -0
  19. package/lib/bvFetch/README.md +101 -0
  20. package/lib/bvFetch/index.js +383 -0
  21. package/lib/checkHighContrast/README.md +26 -0
  22. package/lib/checkHighContrast/index.js +36 -0
  23. package/lib/cookie/README.md +29 -0
  24. package/lib/cookie/index.js +111 -0
  25. package/lib/cookieConsent/README.md +41 -0
  26. package/lib/cookieConsent/index.js +227 -0
  27. package/lib/cssLoadChecker/README.md +19 -0
  28. package/lib/cssLoadChecker/index.js +72 -0
  29. package/lib/date.now/README.md +11 -0
  30. package/lib/date.now/index.js +40 -0
  31. package/lib/domainPolice/README.md +66 -0
  32. package/lib/domainPolice/index.js +95 -0
  33. package/lib/evented/README.md +42 -0
  34. package/lib/evented/index.js +135 -0
  35. package/lib/getOriginalConstructor/README.md +16 -0
  36. package/lib/getOriginalConstructor/index.js +52 -0
  37. package/lib/global/README.md +10 -0
  38. package/lib/global/index.js +48 -0
  39. package/lib/ie/README.md +13 -0
  40. package/lib/ie/index.js +25 -0
  41. package/lib/loader/README.md +73 -0
  42. package/lib/loader/index.js +358 -0
  43. package/lib/logger/README.md +82 -0
  44. package/lib/logger/index.js +180 -0
  45. package/lib/messageFormat/README.md +10 -0
  46. package/lib/messageFormat/index.js +42 -0
  47. package/lib/namespacer/README.md +57 -0
  48. package/lib/namespacer/index.js +98 -0
  49. package/lib/performance/README.md +35 -0
  50. package/lib/performance/entries.js +5 -0
  51. package/lib/performance/getEntries.js +42 -0
  52. package/lib/performance/getEntriesByName.js +61 -0
  53. package/lib/performance/getEntriesByType.js +55 -0
  54. package/lib/performance/index.js +11 -0
  55. package/lib/performance/mark.js +97 -0
  56. package/lib/performance/measure.js +106 -0
  57. package/lib/performance/now.js +63 -0
  58. package/lib/pixelsDisplayed/README.md +19 -0
  59. package/lib/pixelsDisplayed/index.js +113 -0
  60. package/lib/polyfills/README.md +39 -0
  61. package/lib/polyfills/fetch/Headers.js +3 -0
  62. package/lib/polyfills/fetch/Request.js +3 -0
  63. package/lib/polyfills/fetch/Response.js +3 -0
  64. package/lib/polyfills/fetch/fetch.js +3 -0
  65. package/lib/polyfills/fetch/index.js +57 -0
  66. package/lib/polyfills/promise.js +265 -0
  67. package/lib/queryShadowDom/README.md +50 -0
  68. package/lib/queryShadowDom/index.js +93 -0
  69. package/lib/region/README.md +64 -0
  70. package/lib/region/europe/index.js +94 -0
  71. package/lib/region/europe/territories.js +40 -0
  72. package/lib/region/index.js +123 -0
  73. package/lib/staticAssetLoader/README.md +116 -0
  74. package/lib/staticAssetLoader/index.js +248 -0
  75. package/lib/waitForBody/README.md +21 -0
  76. package/lib/waitForBody/index.js +36 -0
  77. package/mkdocs.yaml +5 -0
  78. package/package.json +55 -0
  79. package/test/.eslintrc +5 -0
  80. package/test/fixtures/lib.loader.document-is-wrong-in-ie8.js +5 -0
  81. package/test/fixtures/lib.loader.loadscript-attribute.js +3 -0
  82. package/test/fixtures/lib.loader.loadscript.js +3 -0
  83. package/test/fixtures/lib.loader.loadstylesheet.css +3 -0
  84. package/test/unit/api/.eslintrc +6 -0
  85. package/test/unit/api/index.spec.js +37 -0
  86. package/test/unit/api/response.json +67 -0
  87. package/test/unit/api/statistics.spec.js +218 -0
  88. package/test/unit/application/index.spec.js +313 -0
  89. package/test/unit/body/index.spec.js +15 -0
  90. package/test/unit/bvFetch/index.spec.js +246 -0
  91. package/test/unit/checkHighContrast/index.spec.js +16 -0
  92. package/test/unit/cookie/index.spec.js +191 -0
  93. package/test/unit/cookieConsent/index.spec.js +119 -0
  94. package/test/unit/cssLoadChecker/index.spec.js +75 -0
  95. package/test/unit/date.now/index.spec.js +21 -0
  96. package/test/unit/domainPolice/index.spec.js +141 -0
  97. package/test/unit/evented/index.spec.js +59 -0
  98. package/test/unit/getOriginalConstructor/index.spec.js +60 -0
  99. package/test/unit/global/index.spec.js +84 -0
  100. package/test/unit/ie/index.spec.js +14 -0
  101. package/test/unit/loader/index.spec.js +644 -0
  102. package/test/unit/logger/index.spec.js +141 -0
  103. package/test/unit/messageFormat/index.spec.js +31 -0
  104. package/test/unit/mochaInit.js +8 -0
  105. package/test/unit/namespacer/index.spec.js +100 -0
  106. package/test/unit/performance/getEntries.spec.js +30 -0
  107. package/test/unit/performance/getEntriesByName.spec.js +88 -0
  108. package/test/unit/performance/getEntriesByType.spec.js +48 -0
  109. package/test/unit/performance/index.spec.js +35 -0
  110. package/test/unit/performance/mark.spec.js +40 -0
  111. package/test/unit/performance/measure.spec.js +50 -0
  112. package/test/unit/performance/now.spec.js +21 -0
  113. package/test/unit/pixelsDisplayed/index.spec.js +271 -0
  114. package/test/unit/polyfills/fetch/Headers.js +12 -0
  115. package/test/unit/polyfills/fetch/Request.js +12 -0
  116. package/test/unit/polyfills/fetch/Response.js +12 -0
  117. package/test/unit/polyfills/fetch/fetch.js +12 -0
  118. package/test/unit/polyfills/fetch/index.js +61 -0
  119. package/test/unit/polyfills/promise.spec.js +48 -0
  120. package/test/unit/region/europe/index.spec.js +70 -0
  121. package/test/unit/region/index.spec.js +113 -0
  122. package/test/unit/staticAssetLoader/index.spec.js +215 -0
@@ -0,0 +1,383 @@
1
+ /**
2
+ * @fileOverview
3
+ * Provides api response caching utilties
4
+ */
5
+
6
+ const { fetch } = require('../polyfills/fetch')
7
+
8
+ module.exports = function BvFetch ({ shouldCache, cacheName, cacheLimit, excludeHeaders = [] }) {
9
+ this.shouldCache = shouldCache;
10
+ this.cacheName = cacheName || 'bvCache';
11
+ this.cacheLimit = cacheLimit * 1024 * 1024 || 10 * 1024 * 1024;
12
+ this.fetchPromises = new Map();
13
+ this.cachedRequests = new Set();
14
+ this.excludeHeaders = excludeHeaders;
15
+
16
+ /**
17
+ * Checks if a request is present in a set of cached URLs.
18
+ *
19
+ * @param {Set} cachedRequests - A set of cached request objects.
20
+ * @param {Object} cacheKey - The request object to check for in the cachedRequests set.
21
+ * @param {string} cacheKey.url - The URL of the request.
22
+ * @param {Headers} cacheKey.headers - The headers of the request.
23
+ * @returns {boolean} - Returns true if the request is found in the cachedRequests set, otherwise false.
24
+ */
25
+ function isRequestInSet (cachedRequests, cacheKey) {
26
+ try {
27
+ // Convert the Set to an array and check if any request matches
28
+ return [...cachedRequests].some((cachedRequest) => {
29
+ // Compare URLs
30
+ if (cachedRequest.url !== cacheKey.url) {
31
+ return false;
32
+ }
33
+
34
+ // Compare headers
35
+ const cachedHeaders = [...cachedRequest.headers.entries()];
36
+ const keyHeaders = [...cacheKey.headers.entries()];
37
+
38
+ if (cachedHeaders.length !== keyHeaders.length) {
39
+ return false; // Different number of headers
40
+ }
41
+ // Check if all headers match
42
+ return cachedHeaders.every(([key, value]) => {
43
+ return cacheKey.headers.get(key) === value;
44
+ });
45
+ });
46
+ }
47
+ catch (error) {
48
+ console.warn('Error checking in if request is in cache: ', error);
49
+ return false;
50
+ }
51
+ }
52
+
53
+
54
+ /**
55
+ * Creates a new Request object with the given URL and options.
56
+ *
57
+ * @param {string} url - The URL to which the request is sent.
58
+ * @param {Object} options - The options to apply to the request.
59
+ * @returns {Request} The created Request object.
60
+ */
61
+
62
+ /**
63
+ * Generates a cache key as a Request object for the given URL and options.
64
+ * Filters out headers specified in `excludeHeaders` from the options before creating the Request.
65
+ *
66
+ * @param {string} url - The URL of the API endpoint.
67
+ * @param {Object} options - Optional request options (e.g., headers, method, etc.).
68
+ * @returns {Request} The generated Request object to be used as a cache key.
69
+ */
70
+ this.generateCacheKey = (url, options) => {
71
+ const filteredOptions = Object.assign({}, options);
72
+ if (filteredOptions.headers) {
73
+ const newHeaders = new Headers();
74
+ for (const [key, value] of Object.entries(filteredOptions.headers)) {
75
+ if (!this.excludeHeaders.includes(key)) {
76
+ newHeaders.set(key, value);
77
+ }
78
+ }
79
+ filteredOptions.headers = newHeaders;
80
+ }
81
+ const key = new Request(url, filteredOptions);
82
+ return key;
83
+ };
84
+
85
+ /**
86
+ * Serializes a request object into a JSON string for use as a cache key.
87
+ * The serialization includes the URL, method, and sorted headers of the request.
88
+ * @param {Request} request - The request object to serialize.
89
+ * @returns {string} A JSON string representing the serialized request.
90
+ */
91
+ this.serializeRequestKey = (request) => {
92
+ const url = request.url;
93
+ const method = request.method || 'GET';
94
+ // Convert headers to a sorted array of [key, value] pairs for consistency
95
+ const headersArr = Array.from(request.headers.entries()).sort(([a], [b]) => a.localeCompare(b));
96
+ return JSON.stringify([url, method, { headers: headersArr }]);
97
+ }
98
+
99
+ /**
100
+ * Retrieves cached Requests from the cache storage associated with the provided cache name.
101
+ * @returns {void}
102
+ */
103
+
104
+ this.retrievecachedRequests = () => {
105
+ // Open the Cache Storage
106
+ caches.open(this.cacheName).then(cache => {
107
+ // Get all cache keys
108
+ cache.keys().then(keys => {
109
+ keys.forEach(request => {
110
+ const headers = {};
111
+ request.headers.forEach((value, key) => {
112
+ if (!this.excludeHeaders.includes(key)) {
113
+ headers[key] = value;
114
+ }
115
+ });
116
+
117
+ // Generate the cache key with headers and URL
118
+ const cacheKey = this.generateCacheKey(request.url, { headers });
119
+ this.cachedRequests.add(cacheKey); // Add to the set
120
+ });
121
+ });
122
+ });
123
+ }
124
+
125
+ //callretrievecachedRequests function to set the cache URL set with the cached URLS
126
+ this.retrievecachedRequests();
127
+
128
+ /**
129
+ * Fetches data from the specified URL, caches the response, and returns the response.
130
+ * @param {string} url - The URL from which to fetch data.
131
+ * @param {string} cacheKey - The cache key associated with the fetched data.
132
+ * @returns {Promise<Response>} A Promise that resolves with the fetched response.
133
+ * @throws {Error} Throws an error if there's any problem fetching the data.
134
+ */
135
+ this.fetchDataAndCache = (url, options = {}, cacheKey) => {
136
+ return fetch(url,options)
137
+ .then((response) => {
138
+ // initiate caching of response and return the response
139
+ this.cacheData(response, cacheKey);
140
+ return response.clone();
141
+ })
142
+ .catch(function (error) {
143
+ throw new Error('Error fetching data: ' + error);
144
+ });
145
+ }
146
+
147
+ /**
148
+ * Caches the provided response with the specified cache key if it meets the criteria for caching.
149
+ * @param {Response} response - The response object to be cached.
150
+ * @param {string} cacheKey - The cache key associated with the response.
151
+ * @returns {void}
152
+ */
153
+
154
+ this.cacheData = (response, cacheKey) => {
155
+ const errJson = response.clone();
156
+ let canBeCached = true;
157
+ if (!response.ok) {
158
+ // If the response is not ok, we don't cache it
159
+ canBeCached = false;
160
+ return;
161
+ }
162
+ if (!response.headers.has('Cache-Control')) {
163
+ canBeCached = false;
164
+ return;
165
+ }
166
+ // Check for error in response obj
167
+ errJson.json().then(json => {
168
+ if (typeof this.shouldCache === 'function') {
169
+ canBeCached = this.shouldCache(json);
170
+ }
171
+ }).catch(() => {
172
+ canBeCached = false;
173
+ }).then(() => {
174
+ if (canBeCached) {
175
+ const clonedResponse = response.clone();
176
+ const sizeCheck = response.clone();
177
+ const newHeaders = new Headers();
178
+ clonedResponse.headers.forEach((value, key) => {
179
+ newHeaders.append(key, value);
180
+ });
181
+ newHeaders.append('X-Bazaarvoice-Cached-Time', Date.now())
182
+ // Get response text to calculate its size
183
+ sizeCheck.text().then(text => {
184
+ // Calculate size of response text in bytes
185
+ const sizeInBytes = new Blob([text]).size;
186
+
187
+ // Append response size to headers
188
+ newHeaders.append('X-Bazaarvoice-Response-Size', sizeInBytes);
189
+
190
+ // Create new Response object with modified headers
191
+ const newResponse = new Response(clonedResponse._bodyBlob || clonedResponse.body, {
192
+ status: clonedResponse.status,
193
+ statusText: clonedResponse.statusText,
194
+ headers: newHeaders
195
+ });
196
+ // Cache the response
197
+ caches.open(this.cacheName).then(cache => {
198
+ cache.put(cacheKey, newResponse);
199
+ //add key to cachedRequests set
200
+ this.cachedRequests.add(cacheKey);
201
+ });
202
+ });
203
+ }
204
+ })
205
+ }
206
+
207
+ /**
208
+ * Function to fetch data from cache.
209
+ * @param {string} cacheKey - The cache key to fetch data from the cache.
210
+ * @returns {Promise<Response|null>} A Promise that resolves with a Response object if the data is found in cache,
211
+ * or null if the data is not cached or expired.
212
+ * @throws {Error} Throws an error if there's any problem fetching from cache.
213
+ */
214
+ this.fetchFromCache = (cacheKey) => {
215
+ // Check if the URL is in the set of cached requests set
216
+ if (!isRequestInSet(this.cachedRequests, cacheKey)) {
217
+ return Promise.resolve(null);
218
+ }
219
+
220
+ // Open the cache and try to match the URL
221
+ return caches.open(this.cacheName)
222
+ .then((cache) => {
223
+ return cache.match(cacheKey)
224
+ .then((cachedResponse) => {
225
+ if (!cachedResponse) {
226
+ this.cachedRequests.delete(cacheKey)
227
+ return Promise.resolve(null);
228
+ }
229
+ const cachedTime = cachedResponse.headers.get('X-Bazaarvoice-Cached-Time');
230
+ const ttl = cachedResponse.headers.get('Cache-Control').match(/max-age=(\d+)/)[1];
231
+ const currentTimestamp = Date.now();
232
+ const cacheAge = (currentTimestamp - cachedTime) / 1000;
233
+ if (cacheAge < ttl) {
234
+ // Cached response found
235
+ return cachedResponse.clone();
236
+ }
237
+ })
238
+ })
239
+ .catch((error) => {
240
+ throw new Error('Error fetching from cache: ' + error);
241
+ });
242
+ }
243
+
244
+ /**
245
+ * Fetches data from the API endpoint, caches responses, and handles caching logic.
246
+ * @param {string} url - The URL of the API endpoint.
247
+ * @param {Object} options - Optional request options.
248
+ * @returns {Promise<Response>} A promise resolving to the API response.
249
+ */
250
+
251
+ this.bvFetchFunc = (url, options = {}) => {
252
+
253
+ const cacheKey = this.generateCacheKey(url, options);
254
+ // If an ongoing fetch promise exists for the URL, return it
255
+ if (this.fetchPromises.has(this.serializeRequestKey(cacheKey))) {
256
+ return this.fetchPromises.get(this.serializeRequestKey(cacheKey)).then(res => res.clone());
257
+ }
258
+
259
+ // Check if response is available in cache
260
+ const newPromise = this.fetchFromCache(cacheKey)
261
+ .then((cachedResponse) => {
262
+ // If response found in cache, return it
263
+ if (cachedResponse) {
264
+ return cachedResponse;
265
+ }
266
+ // If response not found in cache, fetch from API and cache it
267
+ return this.fetchDataAndCache(url, options, cacheKey);
268
+ });
269
+
270
+ // Store the ongoing fetch promise
271
+ this.fetchPromises.set(this.serializeRequestKey(cacheKey), newPromise);
272
+
273
+ //initiate cache cleanUp
274
+ this.debounceCleanupExpiredCache();
275
+
276
+ // When fetch completes or fails, remove the promise from the store
277
+ newPromise.finally(() => {
278
+ this.fetchPromises.delete(this.serializeRequestKey(cacheKey));
279
+ });
280
+
281
+ return newPromise.then(res => res.clone());
282
+ }
283
+
284
+
285
+ /**
286
+ * Clears all cache entries stored in the cache storage.
287
+ * @returns {Promise<void>} A promise indicating cache flush completion.
288
+ */
289
+
290
+ this.flushCache = () => {
291
+ return caches.open(this.cacheName).then(cache => {
292
+ return cache.keys().then(keys => {
293
+ const deletionPromises = keys.map(key => cache.delete(key));
294
+ return Promise.all(deletionPromises);
295
+ });
296
+ });
297
+ };
298
+
299
+ this.manageCache = () => {
300
+ // Delete expired cache entries
301
+ caches.open(this.cacheName).then(cache => {
302
+ cache.keys().then(keys => {
303
+ keys.forEach(key => {
304
+ cache.match(key).then(response => {
305
+ const cachedTime = response.headers.get('X-Bazaarvoice-Cached-Time');
306
+ const ttl = response.headers.get('Cache-Control').match(/max-age=(\d+)/)[1];
307
+ const currentTimestamp = Date.now();
308
+ const cacheAge = (currentTimestamp - cachedTime) / 1000;
309
+ if (cacheAge >= ttl) {
310
+ cache.delete(key);
311
+ this.cachedRequests.delete(key);
312
+ }
313
+ });
314
+ });
315
+ });
316
+ });
317
+
318
+ // Calculate total size of cached responses
319
+ let totalSize = 0;
320
+ caches.open(this.cacheName).then(cache => {
321
+ cache.keys().then(keys => {
322
+ // Create an array of promises for cache match operations
323
+ const matchPromises = keys.map(key =>
324
+ cache.match(key).then(response => {
325
+ const sizeHeader = response.headers.get('X-Bazaarvoice-Response-Size');
326
+ return parseInt(sizeHeader, 10);
327
+ })
328
+ );
329
+
330
+ // wait for all match promises to resolve
331
+ return Promise.all(matchPromises)
332
+ .then(sizes => sizes.reduce((acc, size) => acc + size, 0));
333
+ }).then(size => {
334
+ totalSize = size;
335
+ // If total size exceeds 10 MB, delete old cache entries
336
+ if (totalSize > this.cacheLimit) {
337
+
338
+ // create an array of cached responses
339
+ const cacheEntries = [];
340
+ return cache.keys().then(keys => {
341
+ const cachesResEntries = keys.map(key =>
342
+ cache.match(key).then(response => {
343
+ const sizeHeader = response.headers.get('X-Bazaarvoice-Response-Size');
344
+ const lastAccessedTime = response.headers.get('X-Bazaarvoice-Cached-Time');
345
+ cacheEntries.push({ key, size: parseInt(sizeHeader, 10), lastAccessedTime });
346
+ })
347
+ );
348
+
349
+ return Promise.all(cachesResEntries)
350
+ .then(() => {
351
+ // Sort cache entries by last accessed time in ascending order
352
+ cacheEntries.sort((a, b) => a.lastAccessedTime - b.lastAccessedTime);
353
+
354
+ // Delete older cache entries until total size is under 10 MB
355
+ let currentSize = totalSize;
356
+ cacheEntries.forEach(entry => {
357
+ if (currentSize > this.cacheLimit) {
358
+ cache.delete(entry.key);
359
+ this.cachedRequests.delete(entry.key);
360
+ currentSize -= entry.size;
361
+ }
362
+ });
363
+ });
364
+ });
365
+ }
366
+ });
367
+ });
368
+ };
369
+
370
+
371
+ function debounce (func, delay) {
372
+ let timer;
373
+ return function () {
374
+ clearTimeout(timer);
375
+ timer = setTimeout(() => {
376
+ func.apply(this, arguments);
377
+ }, delay);
378
+ };
379
+ }
380
+
381
+ this.debounceCleanupExpiredCache = debounce(this.manageCache, 8000);
382
+
383
+ }
@@ -0,0 +1,26 @@
1
+ # checkHighContrast
2
+
3
+ This is a small method to do the somewhat complicated job of figuring out
4
+ whether a browser is operating in high contrast mode. The end goal is to be
5
+ able to style the page differently so these users.
6
+
7
+ # Limitations
8
+
9
+ This works on all Windows browsers but only Firefox on Mac. The way this works
10
+ is by detecting when the browser's computed styles are different than the
11
+ given ones. In Windows, the high contrast theme coerces the browsers to ignore
12
+ a website's given styles in favor of its own. In OSX, the system level high
13
+ contrast settings will alter the entire display at a lower level so browsers
14
+ won't be aware of it and therefore neither will we. Firefox has options in
15
+ the content pane of preferences to ignore website's styles and will behave
16
+ similarly to Windows at that point. The likelihood of Apple changing their
17
+ approach anytime soon is probably small.
18
+
19
+ ## Usage
20
+ ```javascript
21
+ var checkHighContrast = require('checkHighContrast');
22
+
23
+ if( checkHighContrast(body) ) {
24
+ // ... setup alternative styles here ...
25
+ }
26
+ ```
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @fileOverview Utility for determining if browser is in highcontrast mode
3
+ * Originally from Firebird's util directory.
4
+ *
5
+ * High contrast mode overwrites a website's choice of colors with a user's
6
+ * or OS's. This naturally can play havoc with the visual display of information.
7
+ * Detecting and using alternative styles can improve a user's experience.
8
+ */
9
+
10
+ function checkHighContrast (body) {
11
+ var div = document.createElement('div');
12
+ div.style['background-color'] = 'blue';
13
+ body.appendChild(div);
14
+ // Some IE's do not have access to getComputedStyle and need to use
15
+ // elem.currentStyle instead. The results are not the same but either
16
+ // option should reveal whether the browser is interfering.
17
+ var styleAccessor = (window.getComputedStyle && window.getComputedStyle(div)) || div.currentStyle;
18
+ var color = styleAccessor['background-color'];
19
+
20
+ body.removeChild(div);
21
+
22
+ // We may get back the color in an rgb format, we should consider that acceptable
23
+ if (color === 'rgb(0, 0, 255)') {
24
+ return false;
25
+ }
26
+
27
+ if (color === 'blue') {
28
+ return false;
29
+ }
30
+
31
+ // At this point, the color isn't one of the two possible valid results for
32
+ // blue, so we're assuming that high-contrast mode is altering our visual.
33
+ return true;
34
+ }
35
+
36
+ module.exports = checkHighContrast;
@@ -0,0 +1,29 @@
1
+ # cookie
2
+
3
+ The cookie module provides methods for interacting with browser cookies.
4
+
5
+ ```js
6
+ var cookie = require('bv-ui-core/lib/cookie');
7
+
8
+ cookie.create('RememberMe', '1', 365);
9
+ console.log(cookie.read('RememberMe')); // '1'
10
+ cookie.remove('RememberMe');
11
+ ```
12
+
13
+ ## The following methods are provided:
14
+
15
+ - `read(name)`: Read the cookie with the given name.
16
+ - `create(name, value, [days, domain, secure])`: Write a cookie with the given
17
+ name and value. Set the expiration in days using the `days` argument; set
18
+ the domain using the `domain` argument; indicate that the cookie is secure
19
+ by passing `true` as the `secure` argument. Note that if one optional
20
+ argument is provided, all previous arguments must be provided as well.
21
+ - `remove(name)`: Delete the cookie with the given name.
22
+
23
+ ## Usage with `cookieConsent`:
24
+
25
+ - Call `cookieConsent.initConsent` before calling `cookie.create`.
26
+ - Cookies will get created only if the consent for that cookie is true.
27
+ - Each cookie will automatically subscribe to `enable` and `disable` consent events for that cookie.
28
+ - Cookie will get set when consent is `true`.
29
+ - Cookie will get removed when consent is `false`.
@@ -0,0 +1,111 @@
1
+ /**
2
+ * @fileOverview
3
+ * Provides cookie utilities.
4
+ */
5
+
6
+ // Imports.
7
+ var global = require('../global');
8
+ var cookieConsent = require('../cookieConsent');
9
+ // Store to hold cookie values
10
+ var store = {};
11
+ /**
12
+ * Create a cookie.
13
+ *
14
+ * @param {String} name The cookie name.
15
+ * @param {String} value The cookie value.
16
+ * @param {Number} days The cookie lifespan in days.
17
+ * @param {String} [domain] The domain for the cookie.
18
+ * @param {Boolean} [secure] Whether this is a secure cookie.
19
+ * @param {String} [sameSite='Lax'] The SameSite attribute ('Strict', 'Lax', or 'None'). Defaults to 'Lax'.
20
+ */
21
+ function createCookie (name, value, days, domain, secure, sameSite = 'Lax') {
22
+ var date = new Date();
23
+
24
+ date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
25
+ var expires = days ? ';expires=' + date.toGMTString() : '';
26
+
27
+ // Determine if the cookie should be secure.
28
+ // Force the Secure flag if the page is loaded over HTTPS, OR if the explicit `secure` argument is true.
29
+ // This ensures that all cookies (including BVBRANDID) set by this library are secure in production environments.
30
+ var isSecure = secure || (global.location && global.location.protocol === 'https:');
31
+
32
+ // SameSite=None requires the Secure flag, so we fallback to 'Lax' if not secure.
33
+ var sameSiteValue = (sameSite === 'None' && !isSecure) ? 'Lax' : sameSite;
34
+
35
+ var c = encodeURIComponent(name) + '=' +
36
+ encodeURIComponent(value) +
37
+ expires +
38
+ ';path=/' +
39
+ (domain ? (';domain=' + domain) : '') +
40
+ (isSecure ? ';secure' : '') +
41
+ ';SameSite=' + sameSiteValue;
42
+
43
+ global.document.cookie = c;
44
+ }
45
+ /**
46
+ * Obtain the value of a cookie.
47
+ *
48
+ * @param {String} name The cookie name.
49
+ * @return {String} The cookie value or null if no such cookie.
50
+ */
51
+ function readCookie (name) {
52
+ var nameEQ = encodeURIComponent(name) + '=';
53
+ var ca = global.document.cookie.split(';');
54
+ var i;
55
+
56
+ for (i = 0; i < ca.length; i++) {
57
+ var c = ca[i];
58
+
59
+ while (c.charAt(0) === ' ') {
60
+ c = c.substring(1, c.length);
61
+ }
62
+
63
+ if (c.indexOf(nameEQ) === 0) {
64
+ return decodeURIComponent(c.substring(nameEQ.length, c.length));
65
+ }
66
+ }
67
+
68
+ return null;
69
+ }
70
+ /**
71
+ * Remove a cookie.
72
+ *
73
+ * @param {String} name The cookie name.
74
+ */
75
+ function removeCookie (name, domain) {
76
+ delete store[name];
77
+ if (domain) {
78
+ createCookie(name, '', -1, domain);
79
+ }
80
+ else {
81
+ createCookie(name, '', -1);
82
+ }
83
+ }
84
+
85
+ module.exports = {
86
+ create: function (name, value, days, domain, secure, sameSite) {
87
+ store[name] = value;
88
+ var consentPresent = cookieConsent.getConsent(name);
89
+ if (consentPresent) {
90
+ createCookie(name, value, days, domain, secure, sameSite);
91
+ }
92
+ cookieConsent.subscribe(name, 'add', function (consent) {
93
+ if (consent) {
94
+ createCookie(name, value, days, domain, secure, sameSite);
95
+ }
96
+ else {
97
+ removeCookie(name, domain);
98
+ }
99
+ });
100
+
101
+ cookieConsent.subscribe(name, 'enable', function () {
102
+ createCookie(name, value, days, domain, secure, sameSite);
103
+ });
104
+
105
+ cookieConsent.subscribe(name, 'disable', function () {
106
+ removeCookie(name, domain);
107
+ });
108
+ },
109
+ read: readCookie,
110
+ remove: removeCookie
111
+ };
@@ -0,0 +1,41 @@
1
+ # cookieConsent
2
+
3
+ The cookieConsent module provides methods for controlling cookie consents.
4
+
5
+ ```js
6
+ var cookieConsent = require('bv-ui-core/lib/cookieConsent');
7
+ // Initialize
8
+ /**
9
+ * 2nd parameter is to disable/enable consent mechanism.
10
+ * Passing true will disable the consent mechanism.
11
+ */
12
+ cookieConsent.initConsent({
13
+ cookie1: false,
14
+ cookie2: true
15
+ }, false);
16
+
17
+ // Set cookie consent
18
+ cookieConsent.setConsent({ cookie1: true });
19
+
20
+ // Get cookie consent
21
+ cookieConsent.getConsent('cookie1');
22
+
23
+ // Subscribe to consent 'add' event. Triggers when a new cookie consent is added
24
+ cookieConsent.subscribe('cookie3', 'add', function (data) {});
25
+
26
+ // Subscribe to consent 'enable' event. Triggers when a cookie consent is set to true
27
+ cookieConsent.subscribe('cookie3', 'enable', function (data) {});
28
+
29
+ // Valid events that can be subscribed to are 'add', 'enable', 'disable', and 'change'
30
+ // Subscribe to consent 'disable' event. Triggers when a cookie consent is set to false
31
+ var event = cookieConsent.subscribe('cookie3', 'disable', function (data) {});
32
+
33
+ // Subscribe to the store change event. The latest consent store object is passed as parameter to the callback function
34
+ var event = subscribeToConsentStore(function (store){});
35
+
36
+ // Unsubscribe events
37
+ event.unsubscribe();
38
+
39
+ // Get cookie consent disabled/enabled value.
40
+ cookieConsent.getConsentDisabled();
41
+ ```