@sellwild/react-native-sdk 1.7.4 → 1.8.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/README.md +2 -2
- package/SellwildSDK-RN.podspec +3 -1
- package/android/build.gradle +3 -1
- package/android/src/main/java/com/sellwild/rnsdk/SellwildBannerViewManager.kt +44 -3
- package/android/src/main/java/com/sellwild/rnsdk/SellwildFeedViewManager.kt +71 -10
- package/android/src/main/java/com/sellwild/rnsdk/SellwildModule.kt +18 -0
- package/ios/SellwildBannerViewManager.m +1 -0
- package/ios/SellwildBannerViewManager.swift +14 -2
- package/ios/SellwildFeedViewManager.m +1 -0
- package/ios/SellwildFeedViewManager.swift +18 -11
- package/ios/SellwildRNModule.m +1 -0
- package/ios/SellwildRNModule.swift +14 -0
- package/package.json +4 -6
- package/src/SellwildBanner.tsx +15 -28
- package/src/SellwildFeed.tsx +47 -9
- package/src/appIdentity.ts +2 -3
- package/src/commands.ts +30 -1
- package/src/index.ts +7 -5
- package/src/nativeConfig.ts +34 -0
- package/src/SellwildWidget.tsx +0 -145
- package/src/htmlBuilder.ts +0 -383
package/src/htmlBuilder.ts
DELETED
|
@@ -1,383 +0,0 @@
|
|
|
1
|
-
import type { SellwildConfig, AdSize } from '@sellwild/sdk-core'
|
|
2
|
-
import { resolveListingsUrl } from '@sellwild/sdk-core'
|
|
3
|
-
|
|
4
|
-
const WIDGET_CDN = 'https://widget.sellwild.com'
|
|
5
|
-
|
|
6
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
7
|
-
// Prebid.js WebView pre-configuration
|
|
8
|
-
//
|
|
9
|
-
// This script runs BEFORE prebid.js loads by enqueuing via pbjs.que.
|
|
10
|
-
// It addresses two critical WebView issues:
|
|
11
|
-
//
|
|
12
|
-
// 1. ortb2.app — Prebid.js running in a native WebView must declare itself as
|
|
13
|
-
// in-app inventory (OpenRTB app object) rather than web (site object).
|
|
14
|
-
// Without this, bid requests look like browser traffic; DSPs that buy app
|
|
15
|
-
// inventory separately will not bid, and app-ads.txt enforcement is bypassed.
|
|
16
|
-
//
|
|
17
|
-
// 2. userSync iframe filtering — Third-party cookies are blocked in all native
|
|
18
|
-
// WebViews (WKWebView, Android WebView). Iframe-based cookie syncs will
|
|
19
|
-
// always fail silently, wasting network requests and adding latency. Image
|
|
20
|
-
// pixel syncs may still work for some bidders. A longer syncDelay gives the
|
|
21
|
-
// auction time to complete before sync requests compete for bandwidth.
|
|
22
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
23
|
-
function buildPrebidPreConfigScript(config: SellwildConfig): string {
|
|
24
|
-
const ortb2App: Record<string, unknown> = {
|
|
25
|
-
publisher: { id: config.partnerCode },
|
|
26
|
-
}
|
|
27
|
-
if (config.appBundleId) ortb2App['bundle'] = config.appBundleId
|
|
28
|
-
if (config.appStoreUrl) ortb2App['storeurl'] = config.appStoreUrl
|
|
29
|
-
|
|
30
|
-
// GDPR / privacy signals — PBS defaults to gdpr=1 (GDPR applies) and
|
|
31
|
-
// blocks all bidder calls if no consent string is present. The SDK must
|
|
32
|
-
// explicitly declare the user's jurisdiction so the server knows whether
|
|
33
|
-
// to enforce consent. The host app provides gdprApplies and tcString
|
|
34
|
-
// via SellwildConfig; default is gdpr=0 (US traffic, not subject).
|
|
35
|
-
const ortb2Regs: Record<string, unknown> = {
|
|
36
|
-
ext: { gdpr: (config as any).gdprApplies ? 1 : 0 },
|
|
37
|
-
}
|
|
38
|
-
const ortb2User: Record<string, unknown> = {}
|
|
39
|
-
if ((config as any).gdprApplies && (config as any).tcString) {
|
|
40
|
-
ortb2User['ext'] = { consent: (config as any).tcString }
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
let s2sConfigBlock = ''
|
|
44
|
-
if (config.prebidServer) {
|
|
45
|
-
const ps = config.prebidServer
|
|
46
|
-
const s2s = {
|
|
47
|
-
accountId: ps.accountId,
|
|
48
|
-
bidders: ps.bidders,
|
|
49
|
-
timeout: ps.timeout ?? 1500,
|
|
50
|
-
adapter: 'prebidServer',
|
|
51
|
-
endpoint: { p1Consent: ps.endpoint, noP1Consent: ps.endpoint },
|
|
52
|
-
...(ps.syncEndpoint
|
|
53
|
-
? { syncEndpoint: { p1Consent: ps.syncEndpoint, noP1Consent: ps.syncEndpoint } }
|
|
54
|
-
: {}),
|
|
55
|
-
}
|
|
56
|
-
s2sConfigBlock = `,
|
|
57
|
-
// Route all Prebid bidder calls through Prebid Server (S2S mode).
|
|
58
|
-
// Solves cookie/IDFA limitations — the auction runs server-to-server.
|
|
59
|
-
s2sConfig: ${JSON.stringify(s2s)}`
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return `
|
|
63
|
-
<script>
|
|
64
|
-
// Prebid.js WebView pre-configuration — runs before prebid.js initialises.
|
|
65
|
-
window.pbjs = window.pbjs || {};
|
|
66
|
-
window.pbjs.que = window.pbjs.que || [];
|
|
67
|
-
window.pbjs.que.push(function() {
|
|
68
|
-
window.pbjs.setConfig({
|
|
69
|
-
// Declare in-app inventory so DSPs bid on app traffic, not web traffic.
|
|
70
|
-
// Include regs.ext.gdpr so PBS knows whether to enforce consent.
|
|
71
|
-
ortb2: {
|
|
72
|
-
app: ${JSON.stringify(ortb2App)},
|
|
73
|
-
regs: ${JSON.stringify(ortb2Regs)}${Object.keys(ortb2User).length ? `,
|
|
74
|
-
user: ${JSON.stringify(ortb2User)}` : ''}
|
|
75
|
-
},
|
|
76
|
-
// Iframe cookie syncs always fail in WebViews — disable them.
|
|
77
|
-
// Image pixel syncs may still work for some bidders.
|
|
78
|
-
userSync: {
|
|
79
|
-
filterSettings: {
|
|
80
|
-
iframe: { bidders: '*', filter: 'exclude' }
|
|
81
|
-
},
|
|
82
|
-
syncDelay: 5000
|
|
83
|
-
}${s2sConfigBlock}${config.debug ? `,
|
|
84
|
-
// debug mode
|
|
85
|
-
debug: true` : ''}
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
</script>`
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
92
|
-
// Config → element attributes
|
|
93
|
-
//
|
|
94
|
-
// The sellwild-widget reads configuration from HTML element attributes via
|
|
95
|
-
// withCustomizationsFromElement() in src/providers/Customizations/index.ts.
|
|
96
|
-
// Attribute names can be in any case (kebab-case, camelCase, CONSTANT_CASE).
|
|
97
|
-
// Complex objects are JSON-stringified; arrays are comma-separated.
|
|
98
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
99
|
-
function configToAttributes(config: SellwildConfig): string {
|
|
100
|
-
const parts: string[] = []
|
|
101
|
-
|
|
102
|
-
const add = (name: string, value: unknown) => {
|
|
103
|
-
if (value === undefined || value === null || value === '' || value === false || value === 0) return
|
|
104
|
-
if (typeof value === 'object') {
|
|
105
|
-
parts.push(`${name}='${JSON.stringify(value).replace(/'/g, ''')}'`)
|
|
106
|
-
} else {
|
|
107
|
-
parts.push(`${name}="${String(value)}"`)
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Identity / listings
|
|
112
|
-
add('partner-code', config.partnerCode)
|
|
113
|
-
add('listings', resolveListingsUrl(config))
|
|
114
|
-
|
|
115
|
-
// Disable remote customization fetch — the widget defaults to fetching
|
|
116
|
-
// https://widget.sellwild.com/{partnerCode}/{slug}.json which (a) doesn't
|
|
117
|
-
// exist for SDK consumers and (b) is unnecessary because the SDK supplies
|
|
118
|
-
// every customization via element attributes already.
|
|
119
|
-
parts.push('customize="false"')
|
|
120
|
-
|
|
121
|
-
// Ad system selection — REQUIRED. AdStack.initializeAdStack() switches on
|
|
122
|
-
// theme.adType and silently does nothing if it's unset, meaning Prebid never
|
|
123
|
-
// loads and no auctions ever run. PrebidOnly is the dominant value across
|
|
124
|
-
// production publisher widgets. Override via config.adType if needed.
|
|
125
|
-
add('ad-type', (config as any).adType || 'PrebidOnly')
|
|
126
|
-
|
|
127
|
-
// Display
|
|
128
|
-
add('title', config.title)
|
|
129
|
-
add('link-text', config.linkText)
|
|
130
|
-
add('buy-now-text', config.buyNowText)
|
|
131
|
-
add('title-color', config.titleColor)
|
|
132
|
-
add('title-size', config.titleSize)
|
|
133
|
-
add('link-color', config.linkColor)
|
|
134
|
-
add('link-size', config.linkSize)
|
|
135
|
-
add('font-size', config.fontSize)
|
|
136
|
-
add('font-family', config.fontFamily)
|
|
137
|
-
add('font-color', config.fontColor)
|
|
138
|
-
add('price-color', config.priceColor)
|
|
139
|
-
add('price-font-color', config.priceFontColor)
|
|
140
|
-
add('margin-bottom', config.marginBottom)
|
|
141
|
-
add('card-width', config.cardWidth)
|
|
142
|
-
add('card-height', config.cardHeight)
|
|
143
|
-
add('colors', config.colors?.join(','))
|
|
144
|
-
add('watermark', config.watermark || undefined)
|
|
145
|
-
add('watermark-title', config.watermarkTitle)
|
|
146
|
-
add('overlay-title', config.overlayTitle || undefined)
|
|
147
|
-
add('css', config.css)
|
|
148
|
-
|
|
149
|
-
// Ads – display
|
|
150
|
-
add('gam-tag', config.gamTag)
|
|
151
|
-
add('gam-tag-desc', config.gamTagDesc)
|
|
152
|
-
add('banner-zid', config.bannerZid)
|
|
153
|
-
add('bottom-banner-zid', config.bottomBannerZid)
|
|
154
|
-
add('mobile-banner-zid', config.mobileBannerZid)
|
|
155
|
-
// Filter empties before joining — the widget's parser splits on ',' and
|
|
156
|
-
// does not strip empty strings, so a stray comma yields [""] not [].
|
|
157
|
-
add('mobile-zid', config.mobileZids?.filter(Boolean).join(','))
|
|
158
|
-
add('display-zid', config.displayZids?.filter(Boolean).join(','))
|
|
159
|
-
add('skyscraper-zid', config.skyscraperZid)
|
|
160
|
-
add('hide-banner-top', config.hideBannerTop || undefined)
|
|
161
|
-
add('hide-banner-bottom', config.hideBannerBottom || undefined)
|
|
162
|
-
add('gpt-proxy-url', config.gptProxyUrl)
|
|
163
|
-
add('disable-gpt', config.disableGpt || undefined)
|
|
164
|
-
add('ad-disable-display', config.adDisableDisplay || undefined)
|
|
165
|
-
add('safe-frame', config.safeFrame || undefined)
|
|
166
|
-
|
|
167
|
-
// Ads – refresh
|
|
168
|
-
add('ad-refresh-max', config.adRefreshMax)
|
|
169
|
-
add('ad-refresh-max-mobile', config.adRefreshMaxMobile)
|
|
170
|
-
add('ad-refresh-interval', config.adRefreshInterval)
|
|
171
|
-
add('max-failed-auctions', config.maxFailedAuctions)
|
|
172
|
-
add('prebid-src', config.prebidSrc)
|
|
173
|
-
add('prebid-defer', config.prebidDefer)
|
|
174
|
-
add('floor-multiplier', config.floorMultiplier !== 1 ? config.floorMultiplier : undefined)
|
|
175
|
-
|
|
176
|
-
// Ads – geo
|
|
177
|
-
add('ad-geo-block', config.adGeoBlock)
|
|
178
|
-
add('ad-geo-block-refresh', config.adGeoBlockRefresh)
|
|
179
|
-
|
|
180
|
-
// Ads – compliance
|
|
181
|
-
add('gpp-enabled', config.gppEnabled || undefined)
|
|
182
|
-
add('tcf-version', config.tcfVersion)
|
|
183
|
-
add('consent-management', config.consentManagement)
|
|
184
|
-
add('schain-sid', config.schainSid)
|
|
185
|
-
add('s2s-config', config.s2sConfig)
|
|
186
|
-
add('iab-cats', Array.isArray(config.iabCats) ? config.iabCats.join(',') : config.iabCats)
|
|
187
|
-
|
|
188
|
-
// Third-party (typed fields with defaults — kept emitted explicitly for
|
|
189
|
-
// backwards compatibility with static buildConfig() callers)
|
|
190
|
-
add('boltive', config.boltive || undefined)
|
|
191
|
-
add('boltive-client-id', config.boltiveClientId)
|
|
192
|
-
add('lotame', config.lotame || undefined)
|
|
193
|
-
add('growthcode', config.growthcode)
|
|
194
|
-
add('bh-tag', config.bhTag)
|
|
195
|
-
|
|
196
|
-
// Mobile ad controls
|
|
197
|
-
add('enable-interstitial', config.enableInterstitial || undefined)
|
|
198
|
-
add('enable-fullscreen-video', config.enableFullscreenVideo || undefined)
|
|
199
|
-
add('interstitials-per-session', config.interstitialsPerSession)
|
|
200
|
-
add('video-takeovers-per-session', config.videoTakeoversPerSession)
|
|
201
|
-
|
|
202
|
-
// Debug
|
|
203
|
-
add('debug', config.debug || undefined)
|
|
204
|
-
add('membership-type', config.membershipType)
|
|
205
|
-
|
|
206
|
-
// ─── Remote passthrough ────────────────────────────────────────────────────
|
|
207
|
-
// Forward the raw CDN payload verbatim. The widget's attribute parser is
|
|
208
|
-
// case-insensitive (kebab-case / camelCase / CONSTANT_CASE all work) and
|
|
209
|
-
// accepts unknown keys, so every CMS-defined bidder, waterfall partner, or
|
|
210
|
-
// ad-network setting flows through to the WebView without an SDK release.
|
|
211
|
-
//
|
|
212
|
-
// Skip keys that we already emitted via typed fields above to avoid
|
|
213
|
-
// double-emission. Identity fields (CODE, SLUG, NAME, LISTINGS) are handled
|
|
214
|
-
// by the typed block; everything else (bidders, third-party, etc.) lands
|
|
215
|
-
// here as the canonical CONSTANT_CASE attribute.
|
|
216
|
-
const emittedFromTyped = new Set<string>([
|
|
217
|
-
'CODE', 'SLUG', 'NAME', 'LISTINGS',
|
|
218
|
-
'TITLE', 'LINK_TEXT', 'BUY_NOW_TEXT', 'TITLE_COLOR', 'LINK_COLOR',
|
|
219
|
-
'FONT_FAMILY', 'FONT_URL', 'FONT_COLOR', 'PRICE_COLOR', 'PRICE_FONT_COLOR',
|
|
220
|
-
'MARGIN_BOTTOM', 'CARD_WIDTH', 'OVERLAY_TITLE', 'COLORS', 'CSS',
|
|
221
|
-
'WATERMARK', 'WATERMARK_TITLE',
|
|
222
|
-
'BANNER_ZID', 'BOTTOM_BANNER_ZID', 'MOBILE_BANNER_ZID', 'MOBILE_ZID',
|
|
223
|
-
'DISPLAY_ZID', 'HIDE_BANNER_TOP', 'HIDE_BANNER_BOTTOM', 'GAM',
|
|
224
|
-
'DISABLE_GPT', 'AD_UNITS', 'SAFE_FRAME', 'AD_DISABLE_DISPLAY',
|
|
225
|
-
'AD_REFRESH_MAX', 'AD_REFRESH_MAX_MOBILE', 'AD_REFRESH_INTERVAL',
|
|
226
|
-
'MAX_FAILED_AUCTIONS', 'PREBID_DEFER', 'PREBID_SRC',
|
|
227
|
-
'AD_GEO_BLOCK', 'AD_GEO_BLOCK_REFRESH',
|
|
228
|
-
'GPP_ENABLED', 'TCF_VERSION', 'CONSENT_MANAGEMENT', 'SCHAIN_SID',
|
|
229
|
-
'S2S_CONFIG', 'IAB_CATS',
|
|
230
|
-
'ENABLE_INTERSTITIAL', 'ENABLE_FULLSCREEN_VIDEO',
|
|
231
|
-
'INTERSTITIALS_PER_SESSION', 'VIDEO_TAKEOVERS_PER_SESSION',
|
|
232
|
-
'BOLTIVE', 'BOLTIVE_CLIENT_ID', 'LOTAME', 'GROWTHCODE', 'BH_TAG',
|
|
233
|
-
])
|
|
234
|
-
if (config.remote) {
|
|
235
|
-
for (const [key, value] of Object.entries(config.remote)) {
|
|
236
|
-
if (emittedFromTyped.has(key)) continue
|
|
237
|
-
add(key, value)
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
return parts.join('\n ')
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
245
|
-
// Widget HTML builder
|
|
246
|
-
//
|
|
247
|
-
// The widget JS URL can be:
|
|
248
|
-
// - A publisher-specific bundle: https://widget.sellwild.com/{CODE}/{SLUG}.js
|
|
249
|
-
// (config already baked in at build time; element attributes are optional)
|
|
250
|
-
// - The generic bundle: https://widget.sellwild.com/partner.js
|
|
251
|
-
// (reads all config from element attributes — SDK default)
|
|
252
|
-
//
|
|
253
|
-
// Pass widgetJsUrl in config to override the default generic bundle.
|
|
254
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
255
|
-
export function buildWidgetHtml(config: SellwildConfig & { widgetJsUrl?: string }): string {
|
|
256
|
-
// partner.js is the canonical generic widget bundle. It loads its own Prebid
|
|
257
|
-
// build internally (from cache.sellwild.com), so the SDK MUST NOT inject a
|
|
258
|
-
// separate prebid <script> tag — doing so causes a double-load and breaks
|
|
259
|
-
// header bidding initialization order.
|
|
260
|
-
const widgetSrc = config.widgetJsUrl ?? `${WIDGET_CDN}/partner.js`
|
|
261
|
-
const attrs = configToAttributes(config)
|
|
262
|
-
|
|
263
|
-
const prebidPreConfig = buildPrebidPreConfigScript(config)
|
|
264
|
-
|
|
265
|
-
return `<!DOCTYPE html>
|
|
266
|
-
<html>
|
|
267
|
-
<head>
|
|
268
|
-
<meta charset="utf-8">
|
|
269
|
-
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
|
270
|
-
<style>
|
|
271
|
-
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
272
|
-
html, body { width: 100%; background: transparent; overflow-x: hidden; }
|
|
273
|
-
</style>
|
|
274
|
-
${prebidPreConfig}
|
|
275
|
-
</head>
|
|
276
|
-
<body>
|
|
277
|
-
<sellwild-widget
|
|
278
|
-
${attrs}
|
|
279
|
-
></sellwild-widget>
|
|
280
|
-
|
|
281
|
-
<script>
|
|
282
|
-
(function() {
|
|
283
|
-
function send(type, payload) {
|
|
284
|
-
try {
|
|
285
|
-
window.ReactNativeWebView.postMessage(JSON.stringify(Object.assign({ type: type }, payload || {})));
|
|
286
|
-
} catch(e) {}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// partner/index.tsx calls window.open() on listing tap — intercept ALL
|
|
290
|
-
// calls. Listings link to external sites (eBay, Amazon, dealer sites, etc.)
|
|
291
|
-
// so we can't filter by domain. The widget only uses window.open for listings.
|
|
292
|
-
var _open = window.open;
|
|
293
|
-
window.open = function(url) {
|
|
294
|
-
if (url) {
|
|
295
|
-
send('LISTING_CLICK', { url: url });
|
|
296
|
-
return null;
|
|
297
|
-
}
|
|
298
|
-
return _open.apply(window, arguments);
|
|
299
|
-
};
|
|
300
|
-
|
|
301
|
-
document.addEventListener('DOMContentLoaded', function() {
|
|
302
|
-
setTimeout(function() { send('WIDGET_LOADED'); }, 600);
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
window.addEventListener('error', function(e) {
|
|
306
|
-
send('ERROR', { message: e.message || 'Widget load error' });
|
|
307
|
-
});
|
|
308
|
-
})();
|
|
309
|
-
</script>
|
|
310
|
-
|
|
311
|
-
<script async src="${widgetSrc}"></script>
|
|
312
|
-
</body>
|
|
313
|
-
</html>`
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
317
|
-
// Banner HTML builder
|
|
318
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
319
|
-
export function buildBannerHtml(
|
|
320
|
-
config: SellwildConfig,
|
|
321
|
-
zoneId: number | string,
|
|
322
|
-
size: AdSize
|
|
323
|
-
): string {
|
|
324
|
-
const [width, height] = size.split('x').map(Number)
|
|
325
|
-
const gptSrc = config.gptProxyUrl
|
|
326
|
-
? `${config.gptProxyUrl}/tag/js/gpt.js`
|
|
327
|
-
: 'https://securepubads.g.doubleclick.net/tag/js/gpt.js'
|
|
328
|
-
|
|
329
|
-
const adScript = config.gamTag && !config.disableGpt
|
|
330
|
-
? buildGptScript(config.gamTag, gptSrc, width, height)
|
|
331
|
-
: buildZoneScript(String(zoneId), width, height)
|
|
332
|
-
|
|
333
|
-
return `<!DOCTYPE html>
|
|
334
|
-
<html>
|
|
335
|
-
<head>
|
|
336
|
-
<meta charset="utf-8">
|
|
337
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
338
|
-
<style>
|
|
339
|
-
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
340
|
-
html, body { width: ${width}px; height: ${height}px; overflow: hidden; background: transparent; }
|
|
341
|
-
#ad { width: ${width}px; height: ${height}px; }
|
|
342
|
-
</style>
|
|
343
|
-
</head>
|
|
344
|
-
<body>
|
|
345
|
-
<div id="ad"></div>
|
|
346
|
-
<script>
|
|
347
|
-
function notify(type) {
|
|
348
|
-
try { window.ReactNativeWebView.postMessage(JSON.stringify({ type: type })); } catch(e) {}
|
|
349
|
-
}
|
|
350
|
-
${adScript}
|
|
351
|
-
</script>
|
|
352
|
-
</body>
|
|
353
|
-
</html>`
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
function buildGptScript(gamTag: string, gptSrc: string, w: number, h: number): string {
|
|
357
|
-
return `
|
|
358
|
-
window.googletag = window.googletag || { cmd: [] };
|
|
359
|
-
var s = document.createElement('script');
|
|
360
|
-
s.src = '${gptSrc}'; s.async = true;
|
|
361
|
-
document.head.appendChild(s);
|
|
362
|
-
googletag.cmd.push(function() {
|
|
363
|
-
var slot = googletag.defineSlot('${gamTag}', [${w}, ${h}], 'ad');
|
|
364
|
-
if (slot) {
|
|
365
|
-
slot.addService(googletag.pubads());
|
|
366
|
-
googletag.pubads().enableSingleRequest();
|
|
367
|
-
googletag.pubads().addEventListener('slotRenderEnded', function(e) {
|
|
368
|
-
if (!e.isEmpty) notify('AD_IMPRESSION');
|
|
369
|
-
});
|
|
370
|
-
googletag.enableServices();
|
|
371
|
-
googletag.display('ad');
|
|
372
|
-
}
|
|
373
|
-
});`
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
function buildZoneScript(zoneId: string, w: number, h: number): string {
|
|
377
|
-
return `
|
|
378
|
-
var s = document.createElement('script');
|
|
379
|
-
s.src = 'https://bidstream.sellwild.com/ads?zone=${zoneId}&w=${w}&h=${h}';
|
|
380
|
-
s.async = true;
|
|
381
|
-
s.onload = function() { notify('AD_IMPRESSION'); };
|
|
382
|
-
document.getElementById('ad').appendChild(s);`
|
|
383
|
-
}
|