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.
- package/.eslintrc +40 -0
- package/.travis.yml +5 -0
- package/CONTRIBUTING.md +98 -0
- package/LICENSE.md +13 -0
- package/OWNERS +2 -0
- package/README.md +63 -0
- package/catalog-info.yaml +30 -0
- package/karma.conf.js +130 -0
- package/lib/README.md +61 -0
- package/lib/api/.babelrc +3 -0
- package/lib/api/.eslintrc +9 -0
- package/lib/api/README.md +134 -0
- package/lib/api/index.js +15 -0
- package/lib/api/statistics.js +148 -0
- package/lib/application/README.md +96 -0
- package/lib/application/index.js +171 -0
- package/lib/body/README.md +13 -0
- package/lib/body/index.js +19 -0
- package/lib/bvFetch/README.md +101 -0
- package/lib/bvFetch/index.js +383 -0
- package/lib/checkHighContrast/README.md +26 -0
- package/lib/checkHighContrast/index.js +36 -0
- package/lib/cookie/README.md +29 -0
- package/lib/cookie/index.js +111 -0
- package/lib/cookieConsent/README.md +41 -0
- package/lib/cookieConsent/index.js +227 -0
- package/lib/cssLoadChecker/README.md +19 -0
- package/lib/cssLoadChecker/index.js +72 -0
- package/lib/date.now/README.md +11 -0
- package/lib/date.now/index.js +40 -0
- package/lib/domainPolice/README.md +66 -0
- package/lib/domainPolice/index.js +95 -0
- package/lib/evented/README.md +42 -0
- package/lib/evented/index.js +135 -0
- package/lib/getOriginalConstructor/README.md +16 -0
- package/lib/getOriginalConstructor/index.js +52 -0
- package/lib/global/README.md +10 -0
- package/lib/global/index.js +48 -0
- package/lib/ie/README.md +13 -0
- package/lib/ie/index.js +25 -0
- package/lib/loader/README.md +73 -0
- package/lib/loader/index.js +358 -0
- package/lib/logger/README.md +82 -0
- package/lib/logger/index.js +180 -0
- package/lib/messageFormat/README.md +10 -0
- package/lib/messageFormat/index.js +42 -0
- package/lib/namespacer/README.md +57 -0
- package/lib/namespacer/index.js +98 -0
- package/lib/performance/README.md +35 -0
- package/lib/performance/entries.js +5 -0
- package/lib/performance/getEntries.js +42 -0
- package/lib/performance/getEntriesByName.js +61 -0
- package/lib/performance/getEntriesByType.js +55 -0
- package/lib/performance/index.js +11 -0
- package/lib/performance/mark.js +97 -0
- package/lib/performance/measure.js +106 -0
- package/lib/performance/now.js +63 -0
- package/lib/pixelsDisplayed/README.md +19 -0
- package/lib/pixelsDisplayed/index.js +113 -0
- package/lib/polyfills/README.md +39 -0
- package/lib/polyfills/fetch/Headers.js +3 -0
- package/lib/polyfills/fetch/Request.js +3 -0
- package/lib/polyfills/fetch/Response.js +3 -0
- package/lib/polyfills/fetch/fetch.js +3 -0
- package/lib/polyfills/fetch/index.js +57 -0
- package/lib/polyfills/promise.js +265 -0
- package/lib/queryShadowDom/README.md +50 -0
- package/lib/queryShadowDom/index.js +93 -0
- package/lib/region/README.md +64 -0
- package/lib/region/europe/index.js +94 -0
- package/lib/region/europe/territories.js +40 -0
- package/lib/region/index.js +123 -0
- package/lib/staticAssetLoader/README.md +116 -0
- package/lib/staticAssetLoader/index.js +248 -0
- package/lib/waitForBody/README.md +21 -0
- package/lib/waitForBody/index.js +36 -0
- package/mkdocs.yaml +5 -0
- package/package.json +55 -0
- package/test/.eslintrc +5 -0
- package/test/fixtures/lib.loader.document-is-wrong-in-ie8.js +5 -0
- package/test/fixtures/lib.loader.loadscript-attribute.js +3 -0
- package/test/fixtures/lib.loader.loadscript.js +3 -0
- package/test/fixtures/lib.loader.loadstylesheet.css +3 -0
- package/test/unit/api/.eslintrc +6 -0
- package/test/unit/api/index.spec.js +37 -0
- package/test/unit/api/response.json +67 -0
- package/test/unit/api/statistics.spec.js +218 -0
- package/test/unit/application/index.spec.js +313 -0
- package/test/unit/body/index.spec.js +15 -0
- package/test/unit/bvFetch/index.spec.js +246 -0
- package/test/unit/checkHighContrast/index.spec.js +16 -0
- package/test/unit/cookie/index.spec.js +191 -0
- package/test/unit/cookieConsent/index.spec.js +119 -0
- package/test/unit/cssLoadChecker/index.spec.js +75 -0
- package/test/unit/date.now/index.spec.js +21 -0
- package/test/unit/domainPolice/index.spec.js +141 -0
- package/test/unit/evented/index.spec.js +59 -0
- package/test/unit/getOriginalConstructor/index.spec.js +60 -0
- package/test/unit/global/index.spec.js +84 -0
- package/test/unit/ie/index.spec.js +14 -0
- package/test/unit/loader/index.spec.js +644 -0
- package/test/unit/logger/index.spec.js +141 -0
- package/test/unit/messageFormat/index.spec.js +31 -0
- package/test/unit/mochaInit.js +8 -0
- package/test/unit/namespacer/index.spec.js +100 -0
- package/test/unit/performance/getEntries.spec.js +30 -0
- package/test/unit/performance/getEntriesByName.spec.js +88 -0
- package/test/unit/performance/getEntriesByType.spec.js +48 -0
- package/test/unit/performance/index.spec.js +35 -0
- package/test/unit/performance/mark.spec.js +40 -0
- package/test/unit/performance/measure.spec.js +50 -0
- package/test/unit/performance/now.spec.js +21 -0
- package/test/unit/pixelsDisplayed/index.spec.js +271 -0
- package/test/unit/polyfills/fetch/Headers.js +12 -0
- package/test/unit/polyfills/fetch/Request.js +12 -0
- package/test/unit/polyfills/fetch/Response.js +12 -0
- package/test/unit/polyfills/fetch/fetch.js +12 -0
- package/test/unit/polyfills/fetch/index.js +61 -0
- package/test/unit/polyfills/promise.spec.js +48 -0
- package/test/unit/region/europe/index.spec.js +70 -0
- package/test/unit/region/index.spec.js +113 -0
- package/test/unit/staticAssetLoader/index.spec.js +215 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
var cookieConsent = (function () {
|
|
2
|
+
var init = false;
|
|
3
|
+
var consentDisabled = true;
|
|
4
|
+
var store = {};
|
|
5
|
+
var subscribers = {};
|
|
6
|
+
var events = ['add', 'enable', 'disable', 'change'];
|
|
7
|
+
var storeCallbacks = {};
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* _publish: Calls subscriber callbacks
|
|
12
|
+
* @param {String} consentKey Consent key
|
|
13
|
+
* @param {String} eventName Event name
|
|
14
|
+
* @param {Boolean} data Consent value
|
|
15
|
+
*/
|
|
16
|
+
function _publish (consentKey, eventName, data) {
|
|
17
|
+
if (subscribers[consentKey] && subscribers[consentKey][eventName]) {
|
|
18
|
+
Object.values(subscribers[consentKey][eventName]).forEach(function (callback) {
|
|
19
|
+
callback(data);
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* _publishStore: calls Callbacks with the store object passed
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
function _publishStore () {
|
|
29
|
+
if (Object.values(storeCallbacks).length > 0) {
|
|
30
|
+
Object.values(storeCallbacks).forEach(function (callback) {
|
|
31
|
+
callback(Object.assign({}, store));
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* _set: Set store data
|
|
37
|
+
* @param {String} consentKey Consent key
|
|
38
|
+
* @param {String} consentValue Consent value
|
|
39
|
+
*/
|
|
40
|
+
function _set (consentKey, consentValue) {
|
|
41
|
+
if (typeof consentValue !== 'boolean') {
|
|
42
|
+
throw new TypeError('cookieConsent (setConsent): consent values should be of type boolean. Check value for ' + consentKey + '.');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
var oldValue = store[consentKey];
|
|
46
|
+
|
|
47
|
+
if (oldValue !== consentValue) {
|
|
48
|
+
store[consentKey] = consentValue;
|
|
49
|
+
|
|
50
|
+
if (oldValue === undefined) {
|
|
51
|
+
_publish(consentKey, 'add', consentValue);
|
|
52
|
+
}
|
|
53
|
+
if (oldValue === true) {
|
|
54
|
+
_publish(consentKey, 'disable', consentValue);
|
|
55
|
+
_publish(consentKey, 'change', consentValue);
|
|
56
|
+
}
|
|
57
|
+
else if (oldValue === false) {
|
|
58
|
+
_publish(consentKey, 'enable', consentValue);
|
|
59
|
+
_publish(consentKey, 'change', consentValue);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
_publish(consentKey, 'change', consentValue);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* _unsubscribe: Unsubscribe subscribers
|
|
68
|
+
*/
|
|
69
|
+
function _unsubscribe () {
|
|
70
|
+
if (subscribers[this.consentKey] && subscribers[this.consentKey][this.eventName]) {
|
|
71
|
+
delete subscribers[this.consentKey][this.eventName][this.key];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* _unsubscribeStore: Unsubscribes subscribers from the consent store
|
|
77
|
+
*/
|
|
78
|
+
function _unsubscribeStore () {
|
|
79
|
+
if (storeCallbacks[this.key]) {
|
|
80
|
+
delete storeCallbacks[this.key];
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Get consent disabled
|
|
85
|
+
* @returns Boolean
|
|
86
|
+
*/
|
|
87
|
+
function getConsentDisabled () {
|
|
88
|
+
return consentDisabled
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* initConsent: Initialize the consent store
|
|
92
|
+
* @param {Object} consent Consent object
|
|
93
|
+
* @param {Boolean} disable Disable consent
|
|
94
|
+
* @returns Boolean
|
|
95
|
+
*/
|
|
96
|
+
function initConsent (consent, disable) {
|
|
97
|
+
if (!init) {
|
|
98
|
+
consentDisabled = !!disable;
|
|
99
|
+
|
|
100
|
+
if (consentDisabled) {
|
|
101
|
+
init = true;
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (!(consent && !Array.isArray(consent) && typeof consent === 'object')) {
|
|
106
|
+
throw new TypeError('cookieConsent (init): consent should be an object.');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
var keys = Object.keys(consent);
|
|
110
|
+
|
|
111
|
+
for (var i = 0; i < keys.length; i++) {
|
|
112
|
+
if (typeof consent[keys[i]] !== 'boolean') {
|
|
113
|
+
throw new TypeError('cookieConsent (init): consent values for ' + keys[i] + ' should be of type boolean.');
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
store = Object.assign({}, consent);
|
|
118
|
+
init = true;
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* getConsent: Get consent value from store
|
|
126
|
+
* @param {String} consentKey Consent key
|
|
127
|
+
* @returns Boolean or Undefined
|
|
128
|
+
*/
|
|
129
|
+
function getConsent (consentKey) {
|
|
130
|
+
if (consentDisabled) {
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return store[consentKey];
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* setConsent: Set consent values in the store
|
|
138
|
+
* @param {Object} consent Consent object
|
|
139
|
+
* @returns Boolean
|
|
140
|
+
*/
|
|
141
|
+
function setConsent (consent) {
|
|
142
|
+
if (init && !consentDisabled) {
|
|
143
|
+
if (!(consent && !Array.isArray(consent) && typeof consent === 'object')) {
|
|
144
|
+
throw new TypeError('cookieConsent (setConsent): consent should be an object.')
|
|
145
|
+
}
|
|
146
|
+
var store
|
|
147
|
+
var keys = Object.keys(consent);
|
|
148
|
+
for (var i = 0; i < keys.length; i++) {
|
|
149
|
+
_set(keys[i], consent[keys[i]]);
|
|
150
|
+
}
|
|
151
|
+
var storeCopy=Object.assign({},store)
|
|
152
|
+
if (JSON.stringify(storeCopy)!==JSON.stringify(store)) {
|
|
153
|
+
_publishStore()
|
|
154
|
+
}
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* subscribe: Subscribe to store events
|
|
162
|
+
* @param {String} consentKey Consent key
|
|
163
|
+
* @param {String} eventName Event name
|
|
164
|
+
* @param {Function} callback Event callback
|
|
165
|
+
* @returns Object: Contains unsubscribe method
|
|
166
|
+
*/
|
|
167
|
+
function subscribe (consentKey, eventName, callback) {
|
|
168
|
+
if (typeof consentKey !== 'string') {
|
|
169
|
+
throw new TypeError('cookieConsent (subscribe): consent key should be of type string.');
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (typeof eventName !== 'string') {
|
|
173
|
+
throw new TypeError('cookieConsent (subscribe): event name should be of type string.');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (!events.includes(eventName)) {
|
|
177
|
+
throw new TypeError('cookieConsent (subscribe): event name should be one of ' + events.join(', ') + '.');
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (typeof callback !== 'function') {
|
|
181
|
+
throw new TypeError('cookieConsent (subscribe): callback should be a function.');
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (!subscribers[consentKey]) {
|
|
185
|
+
subscribers[consentKey] = {};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (!subscribers[consentKey][eventName]) {
|
|
189
|
+
subscribers[consentKey][eventName] = {};
|
|
190
|
+
}
|
|
191
|
+
var key = Math.random().toString(36).substr(2, 5);
|
|
192
|
+
|
|
193
|
+
subscribers[consentKey][eventName][key] = callback
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
unsubscribe: _unsubscribe.bind({
|
|
197
|
+
consentKey: consentKey,
|
|
198
|
+
eventName: eventName,
|
|
199
|
+
key: key
|
|
200
|
+
})
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function subscribeToConsentStore (callback) {
|
|
205
|
+
if (typeof callback !== 'function') {
|
|
206
|
+
throw new TypeError('cookieConsent (subscribeToConsentStore): callback should be a function.');
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
var key = Math.random().toString(36).substr(2, 5);
|
|
210
|
+
storeCallbacks[key] = callback;
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
unsubscribe: _unsubscribeStore.bind({ key: key })
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return {
|
|
218
|
+
initConsent: initConsent,
|
|
219
|
+
getConsent: getConsent,
|
|
220
|
+
getConsentDisabled: getConsentDisabled,
|
|
221
|
+
setConsent: setConsent,
|
|
222
|
+
subscribe: subscribe,
|
|
223
|
+
subscribeToConsentStore: subscribeToConsentStore
|
|
224
|
+
};
|
|
225
|
+
})();
|
|
226
|
+
|
|
227
|
+
module.exports = cookieConsent;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# CSS Load Checker
|
|
2
|
+
|
|
3
|
+
This module provides a means of checking if a CSS file has been loaded already or not. It does this by adding a test div to the page and checking the computed styles of it for the `display: none` style.
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
var cssLoadChecker = require('bv-ui-core/lib/cssLoadChecker');
|
|
7
|
+
|
|
8
|
+
if (cssLoadChecker.isCssLoaded('bv-verify-css-loaded')) {
|
|
9
|
+
// do stuff if loaded
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
// do stuff if not loaded (like load it)
|
|
13
|
+
loader.loadStyleSheet(namespace.cssUrl, callback);
|
|
14
|
+
}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The following methods are provided:
|
|
18
|
+
|
|
19
|
+
- `isCssLoaded(className)`: Loads a test div onto the page with the given class name and checks for the style `display: none`. If this is set, then the CSS file is assumed to be present so it returns true. Otherwise, it returns false. The test div is removed before this function finishes executing.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileOverview
|
|
3
|
+
* Provides functions for checking if a stylesheet has been loaded previously
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Imports
|
|
7
|
+
var global = require('../global');
|
|
8
|
+
var body = require('../body');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Function to add the test div to the page
|
|
12
|
+
*
|
|
13
|
+
* @param {string} className - The class name used to check if the css file has loaded yet
|
|
14
|
+
* (does not include the '.' out front, just the name)
|
|
15
|
+
* @return {object} The element that was just created for the purposes of
|
|
16
|
+
* testing whether the CSS has loaded or not
|
|
17
|
+
*/
|
|
18
|
+
var _loadTestDiv = function (className) {
|
|
19
|
+
var testDiv;
|
|
20
|
+
|
|
21
|
+
testDiv = global.document.createElement('div');
|
|
22
|
+
testDiv.style.height = '0px';
|
|
23
|
+
testDiv.style.width = '0px';
|
|
24
|
+
testDiv.style.border = '0px';
|
|
25
|
+
testDiv.className = className;
|
|
26
|
+
body().appendChild(testDiv);
|
|
27
|
+
|
|
28
|
+
return testDiv;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Function to remove the test div from the page
|
|
33
|
+
*
|
|
34
|
+
* @param {object} testDiv - The element that was created for the purposes of
|
|
35
|
+
* testing whether the CSS has loaded or not
|
|
36
|
+
*/
|
|
37
|
+
var _cleanupTestDiv = function (testDiv) {
|
|
38
|
+
testDiv.parentNode.removeChild(testDiv);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
module.exports = {
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Check the test div to see if the styles have loaded
|
|
45
|
+
*
|
|
46
|
+
* @param {string} className - The class name used to check if the css file has loaded yet
|
|
47
|
+
* (does not include the '.' out front, just the name)
|
|
48
|
+
* @return {boolean} True or false as to whether the style sheet has been loaded.
|
|
49
|
+
*/
|
|
50
|
+
isCssLoaded: function (className) {
|
|
51
|
+
var testDiv = _loadTestDiv(className);
|
|
52
|
+
var displayVal;
|
|
53
|
+
var result = false;
|
|
54
|
+
|
|
55
|
+
// add support for IE8
|
|
56
|
+
if (!global.getComputedStyle) {
|
|
57
|
+
displayVal = testDiv.currentStyle['display'];
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
var computedStyles = global.getComputedStyle(testDiv);
|
|
61
|
+
displayVal = computedStyles.getPropertyValue('display');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (displayVal === 'none') {
|
|
65
|
+
result = true;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
_cleanupTestDiv(testDiv);
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Date.now
|
|
2
|
+
|
|
3
|
+
Uses `Date.now` when available and falls back to `new Date().getTime()` when
|
|
4
|
+
needed to get the number of milliseconds elapsed since 1 Jan 1970 00:00:00 UTC.
|
|
5
|
+
|
|
6
|
+
## Usage
|
|
7
|
+
```javascript
|
|
8
|
+
var date = require('date.now');
|
|
9
|
+
|
|
10
|
+
var now = date.now();
|
|
11
|
+
```
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileOverview
|
|
3
|
+
* Provides a unified interface for getting the number of
|
|
4
|
+
* milliseconds elapsed since 1 Jan 1970
|
|
5
|
+
*
|
|
6
|
+
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Imports
|
|
10
|
+
var global = require('../global');
|
|
11
|
+
|
|
12
|
+
// Cache references for speed and to guard against shenanigans
|
|
13
|
+
var nativeDate = global.Date;
|
|
14
|
+
var nativeNow = nativeDate && nativeDate.now;
|
|
15
|
+
|
|
16
|
+
// Is Date.now natively supported?
|
|
17
|
+
var isNativeSupported = (typeof nativeNow === 'function');
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Native Implementation
|
|
21
|
+
* Uses the natively-supported Date.now
|
|
22
|
+
*/
|
|
23
|
+
function nativeImplementation () {
|
|
24
|
+
return nativeNow.call(nativeDate);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Polyfill Implementation
|
|
29
|
+
* Provides similar functionality by using new Date().getTime()
|
|
30
|
+
*/
|
|
31
|
+
function polyfillImplementation () {
|
|
32
|
+
return new nativeDate().getTime(); /*eslint new-cap:0*/
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = {
|
|
36
|
+
now: function () {
|
|
37
|
+
var func = (isNativeSupported) ? nativeImplementation : polyfillImplementation;
|
|
38
|
+
return func();
|
|
39
|
+
}
|
|
40
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# domainPolice
|
|
2
|
+
|
|
3
|
+
The `domainPolice` module provides a function that takes a hostname and an array of
|
|
4
|
+
objects representing a known whitelist of domains, and returns an object with a
|
|
5
|
+
simple API, representing the state of that URL in the whitelist.
|
|
6
|
+
|
|
7
|
+
## Module arguments
|
|
8
|
+
|
|
9
|
+
- `hostname`: The particular hostname to be validated as a string. Ports and protocols are not validated and should not be supplied as part of this. Optimally, this should be provided from `window.location.hostname` in the browser.
|
|
10
|
+
- `allowedDomains`: An array of objects representing whitelisted arrays.
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```javascript
|
|
15
|
+
var domainPolice = require('bv-ui-core/lib/domainPolice');
|
|
16
|
+
|
|
17
|
+
var allowedDomains = [
|
|
18
|
+
{
|
|
19
|
+
domain: '.bazaarvoice.com',
|
|
20
|
+
thirdPartyCookieEnabled: true
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
domain: '.localhost',
|
|
24
|
+
thirdPartyCookieEnabled: false,
|
|
25
|
+
commentsEnabled: true,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
domain: 'no-prefixing-dot.foo.com',
|
|
29
|
+
commentsEnabled: true
|
|
30
|
+
}
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
var bvCop = domainPolice(allowedDomains, 'www.bazaarvoice.com');
|
|
34
|
+
bvCop.isValid; // => true
|
|
35
|
+
bvCop.get('domain'); // => '.bazaarvoice.com'
|
|
36
|
+
bvCop.get('thirdPartyCookieEnabled'); // => true
|
|
37
|
+
bvCop.get('commentsEnabled'); // => undefined
|
|
38
|
+
|
|
39
|
+
var nopeCop = domainPolice(allowedDomains, 'ww.w.foo.com');
|
|
40
|
+
nopeCop.isValid; // => false
|
|
41
|
+
nopeCop.get('anything'); // => undefined
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### `allowedDomains` format
|
|
45
|
+
|
|
46
|
+
`allowedDomains` is an array of objects, and each object is expected to have a
|
|
47
|
+
`domain` property. It may also contain any other arbitrary properties as desired
|
|
48
|
+
for later lookup.
|
|
49
|
+
|
|
50
|
+
Prefixing `.` on the `domain` will allow it to match all subdomains as well.
|
|
51
|
+
URL hosts which include `www.` will be allowed with domain name match.
|
|
52
|
+
|
|
53
|
+
Given the above example, the following domains are all valid:
|
|
54
|
+
|
|
55
|
+
- `bazaarvoice.com`
|
|
56
|
+
- `subdomain.bazaarvoice.com`
|
|
57
|
+
- `localhost`
|
|
58
|
+
- `www-stg.localhost`
|
|
59
|
+
- `no-prefixing-dot.foo.com`
|
|
60
|
+
- `www.no-prefixing-dot.foo.com`
|
|
61
|
+
|
|
62
|
+
Domains that would not be allowed:
|
|
63
|
+
|
|
64
|
+
- `foo.com`
|
|
65
|
+
- `something.foo.com`
|
|
66
|
+
- `bazaarvoice.co.jp`
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileOverview
|
|
3
|
+
* The DomainPolice module is used to provide validation that content is only
|
|
4
|
+
* being loaded on authorized domains.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Returns true if the hostname is an exact match for a specific domain or a
|
|
9
|
+
* suffix match for a wildcard domain (domain starts with a '.').
|
|
10
|
+
*
|
|
11
|
+
* @param {String} domain Domain to check.
|
|
12
|
+
* @param {String} hostname Hostname to check against.
|
|
13
|
+
* @return {Boolean}
|
|
14
|
+
*/
|
|
15
|
+
function domainMatches (domain, hostname) {
|
|
16
|
+
if (domain && (domain.charAt(0) === '.') && hostname) {
|
|
17
|
+
// domainMatches('.domain.com', 'sub.domain.com') and
|
|
18
|
+
// domainMatches('.sub.domain.com', 'sub.domain.com') are both true.
|
|
19
|
+
var index = ('.' + hostname).lastIndexOf(domain);
|
|
20
|
+
return index >= 0 && index === (1 + hostname.length - domain.length);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return hostname === domain || hostname === ('www.' + domain);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Returns the matching domain object if the hostname of the specified URL
|
|
28
|
+
* matches one of the specified domains.
|
|
29
|
+
*
|
|
30
|
+
* @param {Array} domains The set of domain objects to check the URL against
|
|
31
|
+
* @param {String} hostname The hostname to check
|
|
32
|
+
* @return {Object} The matching domain object from the array of provided domains
|
|
33
|
+
*/
|
|
34
|
+
function allowedDomain (domains, hostname) {
|
|
35
|
+
var matchedDomain;
|
|
36
|
+
|
|
37
|
+
for (var i = 0; i < domains.length; i++) {
|
|
38
|
+
if (domainMatches(domains[i].domain, hostname)) {
|
|
39
|
+
matchedDomain = domains[i];
|
|
40
|
+
|
|
41
|
+
return matchedDomain;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// No match found, explicitly returning undefined
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Returns an object that represents a found domain, including the ability to get various attributes off of the associated object from the domains array.
|
|
51
|
+
*
|
|
52
|
+
* @param {Array} domains The set of domain objects to check the URL against
|
|
53
|
+
* @param {String} hostname The hostname to be checked against. Preferably sourced by using window.location.hostname.
|
|
54
|
+
* @return {Object} An object representing the state of the matched domain
|
|
55
|
+
*/
|
|
56
|
+
function domainPolice (domains, hostname) {
|
|
57
|
+
var domainState = {};
|
|
58
|
+
var domain = {
|
|
59
|
+
isValid: false,
|
|
60
|
+
get: function (key) {
|
|
61
|
+
return domainState[key];
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
var domainObject = allowedDomain(domains, hostname);
|
|
66
|
+
|
|
67
|
+
// If we have a matching domain
|
|
68
|
+
if (domainObject) {
|
|
69
|
+
domain.isValid = true;
|
|
70
|
+
|
|
71
|
+
// Manually copying keys, because I can't safely use Object.assign
|
|
72
|
+
// or the npm object-assign module, or even lodash.assign/lodash.extend,
|
|
73
|
+
// as they're assuming ES5 environments.
|
|
74
|
+
//
|
|
75
|
+
// TODO: Once we drop IE11, simplify.
|
|
76
|
+
for (var key in domainObject) {
|
|
77
|
+
if (domainObject.hasOwnProperty(key)) {
|
|
78
|
+
domainState[key] = domainObject[key];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Special case: If the domain is a valid IPv4 address,
|
|
83
|
+
// remove the leading period.
|
|
84
|
+
// The return value here should be used when setting a cookie, and IPv4
|
|
85
|
+
// addresses with a prefixed period do not work for cookie setting like
|
|
86
|
+
// they do for domains.
|
|
87
|
+
if (domainState.domain.match(/^(\.\d+){4}$/)) {
|
|
88
|
+
domainState.domain = domainState.domain.substr(1);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return domain;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
module.exports = domainPolice;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# evented
|
|
2
|
+
|
|
3
|
+
Based on [asEvented][1], the evented module provides a function that can be
|
|
4
|
+
called on a constructor in order to make instances act as event emitters.
|
|
5
|
+
|
|
6
|
+
```js
|
|
7
|
+
var evented = require('bv-ui-core/lib/evented');
|
|
8
|
+
|
|
9
|
+
function Model(config) {
|
|
10
|
+
this.config = config;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
evented.call(Model.prototype);
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
An event emitter provides the following methods:
|
|
17
|
+
|
|
18
|
+
- `on(event, fn)`
|
|
19
|
+
- `off(event, fn)`
|
|
20
|
+
- `one(event, fn)`
|
|
21
|
+
- `once(event, fn)`
|
|
22
|
+
- `trigger(event, *data)`
|
|
23
|
+
|
|
24
|
+
By default, any errors thrown from an event listener are caught and simply logged to the console.
|
|
25
|
+
An alternate behavior can be specified by providing an event handler:
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
var model = new Model({});
|
|
29
|
+
|
|
30
|
+
model.setErrorHandler(function(error, trigger) {
|
|
31
|
+
// The following parameters are available to this function:
|
|
32
|
+
// - error : the value that was thrown, typically an instance of Error
|
|
33
|
+
// - trigger.event : the name of the event passed to trigger()
|
|
34
|
+
// - trigger.data : an array containing the additional arguments passed to trigger()
|
|
35
|
+
// - this : the instance on which trigger() was invoked
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// If you prefer for errors to be thrown from trigger(), then use:
|
|
39
|
+
model.setErrorHandler(function(error) { throw error; });
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
[1]: https://github.com/mkuklis/asEvented
|