• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

prebid / Prebid.js / 16734543791

04 Aug 2025 09:22PM UTC coverage: 96.262% (+33.1%) from 63.163%
16734543791

Pull #13726

github

f6fa0b
web-flow
Merge branch 'master' into dependabot/npm_and_yarn/videojs-playlist-5.2.0
Pull Request #13726: Bump videojs-playlist from 5.1.2 to 5.2.0

39538 of 48585 branches covered (81.38%)

195470 of 203060 relevant lines covered (96.26%)

83.45 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.57
/src/adloader.js
1
import { LOAD_EXTERNAL_SCRIPT } from './activities/activities.js';
2
import { activityParams } from './activities/activityParams.js';
3
import { isActivityAllowed } from './activities/rules.js';
4

5
import { insertElement, logError, logWarn, setScriptAttributes } from './utils.js';
6

7
const _requestCache = new WeakMap();
4✔
8
// The below list contains modules or vendors whom Prebid allows to load external JS.
9
const _approvedLoadExternalJSList = [
4✔
10
  // Prebid maintained modules:
11
  'debugging',
12
  'outstream',
13
  // RTD modules:
14
  'aaxBlockmeter',
15
  'adagio',
16
  'adloox',
17
  'arcspan',
18
  'airgrid',
19
  'browsi',
20
  'brandmetrics',
21
  'clean.io',
22
  'humansecurityMalvDefense',
23
  'humansecurity',
24
  'confiant',
25
  'contxtful',
26
  'hadron',
27
  'mediafilter',
28
  'medianet',
29
  'azerionedge',
30
  'a1Media',
31
  'geoedge',
32
  'qortex',
33
  'dynamicAdBoost',
34
  '51Degrees',
35
  'symitridap',
36
  'wurfl',
37
  'nodalsAi',
38
  'anonymised',
39
  'optable',
40
  // UserId Submodules
41
  'justtag',
42
  'tncId',
43
  'ftrackId',
44
  'id5',
45
];
46

47
/**
48
 * 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
49
 * Each unique URL will be loaded at most 1 time.
50
 * @param {string} url the url to load
51
 * @param {string} moduleType moduleType of the module requesting this resource
52
 * @param {string} moduleCode bidderCode or module code of the module requesting this resource
53
 * @param {function} [callback] callback function to be called after the script is loaded
54
 * @param {Document} [doc] the context document, in which the script will be loaded, defaults to loaded document
55
 * @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.
56
 */
57
export function loadExternalScript(url, moduleType, moduleCode, callback, doc, attributes) {
58
  if (!isActivityAllowed(LOAD_EXTERNAL_SCRIPT, activityParams(moduleType, moduleCode))) {
11✔
59
    return;
1✔
60
  }
61

62
  if (!moduleCode || !url) {
10✔
63
    logError('cannot load external script without url and moduleCode');
1✔
64
    return;
1✔
65
  }
66
  if (!_approvedLoadExternalJSList.includes(moduleCode)) {
9✔
67
    logError(`${moduleCode} not whitelisted for loading external JavaScript`);
1✔
68
    return;
1✔
69
  }
70
  if (!doc) {
8✔
71
    doc = document; // provide a "valid" key for the WeakMap
2✔
72
  }
73
  // only load each asset once
74
  const storedCachedObject = getCacheObject(doc, url);
8✔
75
  if (storedCachedObject) {
8✔
76
    if (callback && typeof callback === 'function') {
3✔
77
      if (storedCachedObject.loaded) {
3!
78
        // invokeCallbacks immediately
79
        callback();
×
80
      } else {
81
        // queue the callback
82
        storedCachedObject.callbacks.push(callback);
3✔
83
      }
84
    }
85
    return storedCachedObject.tag;
3✔
86
  }
87
  const cachedDocObj = _requestCache.get(doc) || {};
5✔
88
  const cacheObject = {
5✔
89
    loaded: false,
90
    tag: null,
91
    callbacks: []
92
  };
93
  cachedDocObj[url] = cacheObject;
5✔
94
  _requestCache.set(doc, cachedDocObj);
5✔
95

96
  if (callback && typeof callback === 'function') {
5✔
97
    cacheObject.callbacks.push(callback);
3✔
98
  }
99

100
  logWarn(`module ${moduleCode} is loading external JavaScript`);
5✔
101
  return requestResource(url, function () {
5✔
102
    cacheObject.loaded = true;
×
103
    try {
×
104
      for (let i = 0; i < cacheObject.callbacks.length; i++) {
×
105
        cacheObject.callbacks[i]();
×
106
      }
107
    } catch (e) {
108
      logError('Error executing callback', 'adloader.js:loadExternalScript', e);
×
109
    }
110
  }, doc, attributes);
111

112
  function requestResource(tagSrc, callback, doc, attributes) {
113
    if (!doc) {
5!
114
      doc = document;
×
115
    }
116
    var jptScript = doc.createElement('script');
5✔
117
    jptScript.type = 'text/javascript';
5✔
118
    jptScript.async = true;
5✔
119

120
    const cacheObject = getCacheObject(doc, url);
5✔
121
    if (cacheObject) {
5✔
122
      cacheObject.tag = jptScript;
5✔
123
    }
124

125
    if (jptScript.readyState) {
5!
126
      jptScript.onreadystatechange = function () {
×
127
        if (jptScript.readyState === 'loaded' || jptScript.readyState === 'complete') {
×
128
          jptScript.onreadystatechange = null;
×
129
          callback();
×
130
        }
131
      };
132
    } else {
133
      jptScript.onload = function () {
5✔
134
        callback();
×
135
      };
136
    }
137

138
    jptScript.src = tagSrc;
5✔
139

140
    if (attributes) {
5✔
141
      setScriptAttributes(jptScript, attributes);
1✔
142
    }
143

144
    // add the new script tag to the page
145
    insertElement(jptScript, doc);
5✔
146

147
    return jptScript;
5✔
148
  }
149
  function getCacheObject(doc, url) {
150
    const cachedDocObj = _requestCache.get(doc);
13✔
151
    if (cachedDocObj && cachedDocObj[url]) {
13✔
152
      return cachedDocObj[url];
8✔
153
    }
154
    return null; // return new cache object?
5✔
155
  }
156
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc