prebid-universal-creative 1.13.0 → 1.14.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.
@@ -1,6 +1,7 @@
1
1
  import * as utils from './utils';
2
2
  import * as domHelper from './domHelper';
3
3
  import {triggerPixel} from './utils';
4
+ import {prebidMessenger} from './messaging.js';
4
5
 
5
6
  const DEFAULT_CACHE_HOST = 'prebid.adnxs.com';
6
7
  const DEFAULT_CACHE_PATH = '/pbc/v1/cache';
@@ -70,10 +71,9 @@ export function newRenderingManager(win, environment) {
70
71
  */
71
72
  function renderCrossDomain(adId, pubAdServerDomain = '', pubUrl) {
72
73
  let windowLocation = win.location;
73
- let parsedUrl = utils.parseUrl(pubUrl);
74
- let publisherDomain = parsedUrl.protocol + '://' + parsedUrl.host;
75
74
  let adServerDomain = pubAdServerDomain || win.location.hostname;
76
75
  let fullAdServerDomain = windowLocation.protocol + '//' + adServerDomain;
76
+ const sendMessage = prebidMessenger(pubUrl, win);
77
77
 
78
78
  function renderAd(ev) {
79
79
  let key = ev.message ? 'message' : 'data';
@@ -84,52 +84,72 @@ export function newRenderingManager(win, environment) {
84
84
  return;
85
85
  }
86
86
 
87
- let origin = ev.origin || ev.originalEvent.origin;
88
87
  if (adObject.message && adObject.message === 'Prebid Response' &&
89
- publisherDomain === origin &&
90
- adObject.adId === adId &&
91
- (adObject.ad || adObject.adUrl)) {
92
- let body = win.document.body;
93
- let ad = adObject.ad;
94
- let url = adObject.adUrl;
95
- let width = adObject.width;
96
- let height = adObject.height;
97
-
98
- if (adObject.mediaType === 'video') {
99
- console.log('Error trying to write ad.');
100
- } else if (ad) {
101
- const iframe = domHelper.getEmptyIframe(adObject.height, adObject.width);
102
- body.appendChild(iframe);
103
- iframe.contentDocument.open();
104
- iframe.contentDocument.write(ad);
105
- iframe.contentDocument.close();
106
- } else if (url) {
107
- const iframe = domHelper.getEmptyIframe(height, width);
108
- iframe.style.display = 'inline';
109
- iframe.style.overflow = 'hidden';
110
- iframe.src = url;
111
-
112
- domHelper.insertElement(iframe, document, 'body');
113
- } else {
114
- console.log(`Error trying to write ad. No ad for bid response id: ${id}`);
88
+ adObject.adId === adId) {
89
+ try {
90
+ let body = win.document.body;
91
+ let ad = adObject.ad;
92
+ let url = adObject.adUrl;
93
+ let width = adObject.width;
94
+ let height = adObject.height;
95
+
96
+ if (adObject.mediaType === 'video') {
97
+ signalRenderResult(false, {
98
+ reason: 'preventWritingOnMainDocument',
99
+ message: `Cannot render video ad ${adId}`
100
+ });
101
+ console.log('Error trying to write ad.');
102
+ } else if (ad) {
103
+ const iframe = domHelper.getEmptyIframe(adObject.height, adObject.width);
104
+ body.appendChild(iframe);
105
+ iframe.contentDocument.open();
106
+ iframe.contentDocument.write(ad);
107
+ iframe.contentDocument.close();
108
+ signalRenderResult(true);
109
+ } else if (url) {
110
+ const iframe = domHelper.getEmptyIframe(height, width);
111
+ iframe.style.display = 'inline';
112
+ iframe.style.overflow = 'hidden';
113
+ iframe.src = url;
114
+
115
+ domHelper.insertElement(iframe, document, 'body');
116
+ signalRenderResult(true);
117
+ } else {
118
+ signalRenderResult(false, {
119
+ reason: 'noAd',
120
+ message: `No ad for ${adId}`
121
+ });
122
+ console.log(`Error trying to write ad. No ad markup or adUrl for ${adId}`);
123
+ }
124
+ } catch (e) {
125
+ signalRenderResult(false, {reason: "exception", message: e.message});
126
+ console.log(`Error in rendering ad`, e);
127
+ }
128
+ }
129
+
130
+ function signalRenderResult(success, {reason, message} = {}) {
131
+ const payload = {
132
+ message: 'Prebid Event',
133
+ adId,
134
+ event: success ? 'adRenderSucceeded' : 'adRenderFailed',
135
+ }
136
+ if (!success) {
137
+ payload.info = {reason, message};
115
138
  }
139
+ sendMessage(payload);
116
140
  }
117
141
  }
118
142
 
143
+
119
144
  function requestAdFromPrebid() {
120
- let message = JSON.stringify({
145
+ let message = {
121
146
  message: 'Prebid Request',
122
147
  adId: adId,
123
148
  adServerDomain: fullAdServerDomain
124
- });
125
- win.parent.postMessage(message, publisherDomain);
126
- }
127
-
128
- function listenAdFromPrebid() {
129
- win.addEventListener('message', renderAd, false);
149
+ }
150
+ sendMessage(message, renderAd);
130
151
  }
131
152
 
132
- listenAdFromPrebid();
133
153
  requestAdFromPrebid();
134
154
  }
135
155
 
@@ -144,7 +164,7 @@ export function newRenderingManager(win, environment) {
144
164
 
145
165
  return `https://${host}${path}`;
146
166
  }
147
-
167
+
148
168
  /**
149
169
  * update iframe by using size string to resize
150
170
  * @param {string} size
package/src/utils.js CHANGED
@@ -32,6 +32,9 @@ export function writeAdUrl(adUrl, width, height) {
32
32
  }
33
33
 
34
34
  export function writeAdHtml(markup) {
35
+ // remove <?xml> and <!doctype> tags
36
+ // https://github.com/prebid/prebid-universal-creative/issues/134
37
+ markup = markup.replace(/\<(\?xml|(\!DOCTYPE[^\>\[]+(\[[^\]]+)?))+[^>]+\>/g, '');
35
38
  postscribe(document.body, markup, {
36
39
  error: console.error
37
40
  });
@@ -1,15 +1,19 @@
1
1
  export const mocks = {
2
2
  createFakeWindow: function (href) {
3
3
  return {
4
+ addEventListener: function () {},
5
+ removeEventListener: function () {},
4
6
  document: {
5
7
  head: {},
6
- body: {}
8
+ body: {
9
+ style: {}
10
+ }
7
11
  },
8
12
  location: {
9
13
  href: href,
10
14
  },
11
15
  parent: {},
12
- top: {}
16
+ top: {},
13
17
  };
14
18
  }
15
- }
19
+ }
@@ -0,0 +1,64 @@
1
+ import {mocks} from '../helpers/mocks.js';
2
+ import {prebidMessenger} from '../../src/messaging.js';
3
+
4
+ describe('prebidMessenger',() => {
5
+ let win;
6
+ beforeEach(() => {
7
+ win = Object.assign(mocks.createFakeWindow(), {
8
+ parent: {
9
+ postMessage: sinon.spy()
10
+ }
11
+ });
12
+ })
13
+ describe('when publisher URL is unavailable', () => {
14
+ let sendMessage;
15
+
16
+ beforeEach(() => {
17
+ sendMessage = prebidMessenger(null, win);
18
+ });
19
+
20
+ it('should throw', () => {
21
+ expect(() => sendMessage('test')).to.throw();
22
+ })
23
+ });
24
+
25
+ describe('when publisher URL is available', () => {
26
+ const URL = 'https://www.publisher.com/page.html';
27
+ const ORIGIN = 'https://www.publisher.com'
28
+ let sendMessage;
29
+ let callback, handler;
30
+
31
+ beforeEach(() => {
32
+ win.addEventListener = function (_, h) {
33
+ handler = h;
34
+ }
35
+ win.removeEventListener = sinon.spy();
36
+ sendMessage = prebidMessenger(URL, win);
37
+ callback = sinon.spy();
38
+ })
39
+
40
+ it('should use origin for postMessage', () => {
41
+ sendMessage('test');
42
+ sinon.assert.calledWith(win.parent.postMessage, JSON.stringify('test'), ORIGIN);
43
+ });
44
+
45
+ it('should not run callback on response if origin does not mach', ()=> {
46
+ sendMessage('test', callback);
47
+ handler({origin: 'different'});
48
+ expect(callback.called).to.be.false;
49
+ });
50
+
51
+ it('should run callback on response if origin does match', () => {
52
+ sendMessage('test', callback);
53
+ const ev = {origin: ORIGIN, data: 'stuff'};
54
+ handler(ev);
55
+ sinon.assert.calledWith(callback, ev);
56
+ });
57
+
58
+ it('should remove window listener when canceled', () => {
59
+ sendMessage('test', callback)();
60
+ expect(win.removeEventListener.called).to.be.true;
61
+ })
62
+
63
+ });
64
+ })