forked from prebid/Prebid.js
-
Notifications
You must be signed in to change notification settings - Fork 7
/
adloader.js
143 lines (132 loc) · 4.02 KB
/
adloader.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import {includes} from './polyfill.js';
import { logError, logWarn, insertElement, setScriptAttributes } from './utils.js';
const _requestCache = new WeakMap();
// The below list contains modules or vendors whom Prebid allows to load external JS.
const _approvedLoadExternalJSList = [
'debugging',
'adloox',
'criteo',
'outstream',
'adagio',
'spotx',
'browsi',
'brandmetrics',
'justtag',
'tncId',
'akamaidap',
'ftrackId',
'inskin',
'hadron',
'medianet',
'improvedigital',
'azerionedge',
'aaxBlockmeter',
'confiant',
'arcspan',
'airgrid',
'clean.io',
'a1Media',
'geoedge',
'mediafilter',
'qortex',
'dynamicAdBoost',
'contxtful',
'id5',
'lucead',
];
/**
* Loads external javascript. Can only be used if external JS is approved by Prebid. See https://github.com/prebid/prebid-js-external-js-template#policy
* Each unique URL will be loaded at most 1 time.
* @param {string} url the url to load
* @param {string} moduleCode bidderCode or module code of the module requesting this resource
* @param {function} [callback] callback function to be called after the script is loaded
* @param {Document} [doc] the context document, in which the script will be loaded, defaults to loaded document
* @param {object} attributes an object of attributes to be added to the script with setAttribute by [key] and [value]; Only the attributes passed in the first request of a url will be added.
*/
export function loadExternalScript(url, moduleCode, callback, doc, attributes) {
if (!moduleCode || !url) {
logError('cannot load external script without url and moduleCode');
return;
}
if (!includes(_approvedLoadExternalJSList, moduleCode)) {
logError(`${moduleCode} not whitelisted for loading external JavaScript`);
return;
}
if (!doc) {
doc = document; // provide a "valid" key for the WeakMap
}
// only load each asset once
const storedCachedObject = getCacheObject(doc, url);
if (storedCachedObject) {
if (callback && typeof callback === 'function') {
if (storedCachedObject.loaded) {
// invokeCallbacks immediately
callback();
} else {
// queue the callback
storedCachedObject.callbacks.push(callback);
}
}
return storedCachedObject.tag;
}
const cachedDocObj = _requestCache.get(doc) || {};
const cacheObject = {
loaded: false,
tag: null,
callbacks: []
};
cachedDocObj[url] = cacheObject;
_requestCache.set(doc, cachedDocObj);
if (callback && typeof callback === 'function') {
cacheObject.callbacks.push(callback);
}
logWarn(`module ${moduleCode} is loading external JavaScript`);
return requestResource(url, function () {
cacheObject.loaded = true;
try {
for (let i = 0; i < cacheObject.callbacks.length; i++) {
cacheObject.callbacks[i]();
}
} catch (e) {
logError('Error executing callback', 'adloader.js:loadExternalScript', e);
}
}, doc, attributes);
function requestResource(tagSrc, callback, doc, attributes) {
if (!doc) {
doc = document;
}
var jptScript = doc.createElement('script');
jptScript.type = 'text/javascript';
jptScript.async = true;
const cacheObject = getCacheObject(doc, url);
if (cacheObject) {
cacheObject.tag = jptScript;
}
if (jptScript.readyState) {
jptScript.onreadystatechange = function () {
if (jptScript.readyState === 'loaded' || jptScript.readyState === 'complete') {
jptScript.onreadystatechange = null;
callback();
}
};
} else {
jptScript.onload = function () {
callback();
};
}
jptScript.src = tagSrc;
if (attributes) {
setScriptAttributes(jptScript, attributes);
}
// add the new script tag to the page
insertElement(jptScript, doc);
return jptScript;
}
function getCacheObject(doc, url) {
const cachedDocObj = _requestCache.get(doc);
if (cachedDocObj && cachedDocObj[url]) {
return cachedDocObj[url];
}
return null; // return new cache object?
}
};