@smoud/playable-sdk 1.0.3 → 1.0.5
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/dist/{index.d.mts → esm/core.d.ts} +2 -4
- package/dist/esm/core.js +517 -0
- package/dist/esm/events.d.ts +4 -0
- package/dist/esm/events.js +58 -0
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +2 -600
- package/dist/esm/protocols.d.ts +9 -0
- package/dist/esm/protocols.js +77 -0
- package/package.json +3 -3
- package/dist/index.d.ts +0 -176
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { EventName } from './events';
|
|
3
2
|
type InitCallbackType = (maxWidth: number, maxHeight: number) => void;
|
|
4
3
|
/**
|
|
5
4
|
* Main SDK class providing playable ad functionality and state management.
|
|
@@ -172,5 +171,4 @@ declare class sdk {
|
|
|
172
171
|
*/
|
|
173
172
|
static off(event: EventName, fn?: Function, context?: any): void;
|
|
174
173
|
}
|
|
175
|
-
|
|
176
|
-
export { sdk as default, sdk };
|
|
174
|
+
export { sdk };
|
package/dist/esm/core.js
ADDED
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
import { emitEvent, offEvent, onEvent } from './events';
|
|
2
|
+
import { isDapi, isMraid, isNucleo, ensureProtocol, isGoogle, isTapjoy, isMintegral, isFacebook, isTikTok } from './protocols';
|
|
3
|
+
const destinationUrl = /android/i.test(navigator.userAgent) ? GOOGLE_PLAY_URL : APP_STORE_URL;
|
|
4
|
+
let isSDKInitialized = false;
|
|
5
|
+
let isProtocolInitialized = false;
|
|
6
|
+
let isForcePaused = false;
|
|
7
|
+
let isInstallClicked = false;
|
|
8
|
+
let initCallback = () => { };
|
|
9
|
+
function bootAd() {
|
|
10
|
+
if (sdk.isReady)
|
|
11
|
+
return;
|
|
12
|
+
emitEvent('boot');
|
|
13
|
+
document.body.oncontextmenu = function () {
|
|
14
|
+
return false;
|
|
15
|
+
};
|
|
16
|
+
initCallback(sdk.maxWidth, sdk.maxHeight);
|
|
17
|
+
emitEvent('ready');
|
|
18
|
+
sdk.isReady = true;
|
|
19
|
+
}
|
|
20
|
+
function changeVolume(value) {
|
|
21
|
+
emitEvent('volume', value);
|
|
22
|
+
}
|
|
23
|
+
function handlePause() {
|
|
24
|
+
changeVolume(0);
|
|
25
|
+
sdk.isPaused = true;
|
|
26
|
+
emitEvent('pause');
|
|
27
|
+
}
|
|
28
|
+
function handleResume() {
|
|
29
|
+
if (isForcePaused)
|
|
30
|
+
return;
|
|
31
|
+
changeVolume(sdk.volume);
|
|
32
|
+
sdk.isPaused = false;
|
|
33
|
+
emitEvent('resume');
|
|
34
|
+
}
|
|
35
|
+
function mraidIsViewable(viewable) {
|
|
36
|
+
if ('mraid' !== AD_PROTOCOL)
|
|
37
|
+
return;
|
|
38
|
+
if (viewable) {
|
|
39
|
+
if (sdk.isReady) {
|
|
40
|
+
handleResume();
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
if (AD_NETWORK == 'ironsource') {
|
|
44
|
+
const maxSize = mraid.getMaxSize();
|
|
45
|
+
sdk.maxWidth = Math.floor(maxSize.width);
|
|
46
|
+
sdk.maxHeight = Math.floor(maxSize.height);
|
|
47
|
+
}
|
|
48
|
+
bootAd();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
handlePause();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function dapiIsViewable(event) {
|
|
56
|
+
if ('dapi' !== AD_PROTOCOL)
|
|
57
|
+
return;
|
|
58
|
+
if (event.isViewable) {
|
|
59
|
+
if (sdk.isReady) {
|
|
60
|
+
handleResume();
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
var screenSize = dapi.getScreenSize();
|
|
64
|
+
screenSize.width = Math.floor(screenSize.width);
|
|
65
|
+
screenSize.height = Math.floor(screenSize.height);
|
|
66
|
+
bootAd();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
handlePause();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function fireResizeEvent(width, height) {
|
|
74
|
+
handleResize(width, height);
|
|
75
|
+
}
|
|
76
|
+
function startMraidProtocol() {
|
|
77
|
+
if ('mraid' !== AD_PROTOCOL)
|
|
78
|
+
return;
|
|
79
|
+
if (!isProtocolInitialized) {
|
|
80
|
+
mraid.removeEventListener('ready', startMraidProtocol);
|
|
81
|
+
mraid.addEventListener('viewableChange', function () {
|
|
82
|
+
var isViewable = mraid.isViewable();
|
|
83
|
+
mraidIsViewable(isViewable);
|
|
84
|
+
});
|
|
85
|
+
if (mraid.isViewable() || AD_NETWORK == 'adcolony') {
|
|
86
|
+
mraidIsViewable(true);
|
|
87
|
+
}
|
|
88
|
+
mraid.addEventListener('audioVolumeChange', function (newVolume) {
|
|
89
|
+
if (newVolume !== null) {
|
|
90
|
+
if (newVolume > 0) {
|
|
91
|
+
changeVolume(sdk.volume);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
changeVolume(0);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
mraid.addEventListener('error', function (t, e) {
|
|
99
|
+
console.log('mraid error: ' + t + ' action: ' + e);
|
|
100
|
+
});
|
|
101
|
+
mraid.addEventListener('sizeChange', function () {
|
|
102
|
+
var maxSize = mraid.getMaxSize();
|
|
103
|
+
fireResizeEvent(maxSize.width, maxSize.height);
|
|
104
|
+
});
|
|
105
|
+
// mraid.addEventListener('stateChange', function (t) {});
|
|
106
|
+
isProtocolInitialized = true;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function startDapiProtocol() {
|
|
110
|
+
if ('dapi' !== AD_PROTOCOL)
|
|
111
|
+
return;
|
|
112
|
+
if (!isProtocolInitialized) {
|
|
113
|
+
dapi.removeEventListener('ready', startDapiProtocol);
|
|
114
|
+
dapi.getAudioVolume();
|
|
115
|
+
dapi.addEventListener('audioVolumeChange', function (volume) {
|
|
116
|
+
var isAudioEnabled = !!volume;
|
|
117
|
+
if (isAudioEnabled) {
|
|
118
|
+
changeVolume(sdk.volume);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
changeVolume(0);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
dapi.addEventListener('adResized', function (event) {
|
|
125
|
+
var maxSize = dapi.getScreenSize();
|
|
126
|
+
fireResizeEvent(event.width || maxSize.width, event.height || maxSize.height);
|
|
127
|
+
});
|
|
128
|
+
if (dapi.isViewable()) {
|
|
129
|
+
dapiIsViewable({ isViewable: true });
|
|
130
|
+
}
|
|
131
|
+
dapi.addEventListener('viewableChange', dapiIsViewable);
|
|
132
|
+
isProtocolInitialized = true;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function startDefaultProtocol() {
|
|
136
|
+
if ('none' !== AD_PROTOCOL)
|
|
137
|
+
return;
|
|
138
|
+
if (!isProtocolInitialized) {
|
|
139
|
+
if ('mintegral' === AD_NETWORK) {
|
|
140
|
+
window.mintGameStart = function () {
|
|
141
|
+
handleResume();
|
|
142
|
+
handleResize(sdk.maxWidth, sdk.maxHeight);
|
|
143
|
+
};
|
|
144
|
+
window.mintGameClose = function () {
|
|
145
|
+
handlePause();
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
document.addEventListener('visibilitychange', () => {
|
|
149
|
+
if (document.visibilityState === 'visible') {
|
|
150
|
+
handleResume();
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
handlePause();
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
if (document.readyState === 'complete') {
|
|
157
|
+
bootAd();
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
window.addEventListener('load', () => {
|
|
161
|
+
bootAd();
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
window.addEventListener('resize', function () {
|
|
165
|
+
handleResize();
|
|
166
|
+
});
|
|
167
|
+
if ('tapjoy' === AD_NETWORK && isTapjoy()) {
|
|
168
|
+
var tapjoyApi = {
|
|
169
|
+
skipAd: function () {
|
|
170
|
+
try {
|
|
171
|
+
sdk.finish();
|
|
172
|
+
}
|
|
173
|
+
catch (e) {
|
|
174
|
+
console.warn('Could not skip ad! | ' + e);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
window.TJ_API.setPlayableAPI && window.TJ_API.setPlayableAPI(tapjoyApi);
|
|
179
|
+
}
|
|
180
|
+
isProtocolInitialized = true;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function finishTapjoy() {
|
|
184
|
+
window.TJ_API.objectiveComplete && window.TJ_API.objectiveComplete();
|
|
185
|
+
window.TJ_API.playableFinished && window.TJ_API.playableFinished();
|
|
186
|
+
window.TJ_API.gameplayFinished && window.TJ_API.gameplayFinished();
|
|
187
|
+
}
|
|
188
|
+
function handleResize(width, height) {
|
|
189
|
+
sdk.maxWidth = Math.floor(width || window.innerWidth);
|
|
190
|
+
sdk.maxHeight = Math.floor(height || window.innerHeight);
|
|
191
|
+
sdk.isLandscape = sdk.maxWidth > sdk.maxHeight;
|
|
192
|
+
emitEvent('resize', sdk.maxWidth, sdk.maxHeight);
|
|
193
|
+
}
|
|
194
|
+
let isListeningToTouchEvents = false;
|
|
195
|
+
let isTouchEventRegistered = false;
|
|
196
|
+
function onUserInteraction(event) {
|
|
197
|
+
if (typeof TouchEvent !== 'undefined' && event instanceof TouchEvent) {
|
|
198
|
+
isListeningToTouchEvents = true;
|
|
199
|
+
}
|
|
200
|
+
if (isListeningToTouchEvents && event instanceof MouseEvent)
|
|
201
|
+
return;
|
|
202
|
+
sdk.interactions += 1;
|
|
203
|
+
emitEvent('interaction', sdk.interactions);
|
|
204
|
+
}
|
|
205
|
+
function registerTouchHandlers() {
|
|
206
|
+
if (!isTouchEventRegistered) {
|
|
207
|
+
document.addEventListener('mousedown', onUserInteraction);
|
|
208
|
+
document.addEventListener('touchstart', onUserInteraction);
|
|
209
|
+
isTouchEventRegistered = true;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Main SDK class providing playable ad functionality and state management.
|
|
214
|
+
* Handles initialization, lifecycle events, and interactions across different ad networks.
|
|
215
|
+
*/
|
|
216
|
+
class sdk {
|
|
217
|
+
/**
|
|
218
|
+
* Initializes the SDK and sets up protocol-specific handlers.
|
|
219
|
+
* This must be called as earlier as possible.
|
|
220
|
+
*
|
|
221
|
+
* @param callback Optional function called when ad container is ready
|
|
222
|
+
* @example
|
|
223
|
+
* // Basic initialization
|
|
224
|
+
* sdk.init();
|
|
225
|
+
*
|
|
226
|
+
* // Initialization with callback
|
|
227
|
+
* sdk.init((width, height) => {
|
|
228
|
+
* new App(width, height)
|
|
229
|
+
* });
|
|
230
|
+
*
|
|
231
|
+
* @fires init When initialization starts
|
|
232
|
+
* @fires boot When the ad begins booting
|
|
233
|
+
* @fires ready When Ad Network is ready and playable ad can be initialized
|
|
234
|
+
*/
|
|
235
|
+
static init(callback) {
|
|
236
|
+
if (isSDKInitialized)
|
|
237
|
+
return;
|
|
238
|
+
ensureProtocol();
|
|
239
|
+
if (callback)
|
|
240
|
+
initCallback = callback;
|
|
241
|
+
if ('mraid' === AD_PROTOCOL && isMraid()) {
|
|
242
|
+
if (mraid.getState() !== 'ready' && 'adcolony' !== AD_NETWORK) {
|
|
243
|
+
mraid.addEventListener('ready', startMraidProtocol);
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
startMraidProtocol();
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
else if ('dapi' === AD_PROTOCOL && isDapi()) {
|
|
250
|
+
window.addEventListener('load', function () {
|
|
251
|
+
dapi.isReady() ? startDapiProtocol() : dapi.addEventListener('ready', startDapiProtocol);
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
startDefaultProtocol();
|
|
256
|
+
}
|
|
257
|
+
emitEvent('init');
|
|
258
|
+
isSDKInitialized = true;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Starts the playable ad experience.
|
|
262
|
+
* Should be called after all resources are loaded and first frame is rendered.
|
|
263
|
+
*
|
|
264
|
+
* @example
|
|
265
|
+
* // Call just after all resources are preloaded and first frame is rendered
|
|
266
|
+
* sdk.start();
|
|
267
|
+
*
|
|
268
|
+
* @fires start When the playable ad starts
|
|
269
|
+
* @fires resize When the ad container is initially sized
|
|
270
|
+
*/
|
|
271
|
+
static start() {
|
|
272
|
+
if (sdk.isStarted)
|
|
273
|
+
return;
|
|
274
|
+
sdk.isStarted = true;
|
|
275
|
+
emitEvent('start');
|
|
276
|
+
registerTouchHandlers();
|
|
277
|
+
if ('mintegral' === AD_NETWORK && isMintegral()) {
|
|
278
|
+
sdk.resize();
|
|
279
|
+
handlePause();
|
|
280
|
+
window.gameReady && window.gameReady();
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
if ('tapjoy' === AD_NETWORK && isTapjoy()) {
|
|
284
|
+
window.TJ_API.setPlayableBuild({
|
|
285
|
+
orientation: this.isLandscape ? 'landscape' : 'portrait',
|
|
286
|
+
buildID: BUILD_HASH
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
sdk.resize();
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Marks the playable ad as finished.
|
|
294
|
+
* This triggers network-specific completion handlers.
|
|
295
|
+
*
|
|
296
|
+
* @example
|
|
297
|
+
* // Call when game/experience is complete
|
|
298
|
+
* sdk.finish();
|
|
299
|
+
*
|
|
300
|
+
* @fires finish When the playable ad is marked as finished
|
|
301
|
+
*/
|
|
302
|
+
static finish() {
|
|
303
|
+
sdk.isFinished = true;
|
|
304
|
+
if ('tapjoy' === AD_NETWORK && isTapjoy()) {
|
|
305
|
+
finishTapjoy();
|
|
306
|
+
}
|
|
307
|
+
else if ('mintegral' === AD_NETWORK && isMintegral()) {
|
|
308
|
+
window.gameEnd && window.gameEnd();
|
|
309
|
+
}
|
|
310
|
+
else if ('vungle' === AD_NETWORK) {
|
|
311
|
+
parent.postMessage('complete', '*');
|
|
312
|
+
}
|
|
313
|
+
emitEvent('finish');
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Triggers a retry/restart of the playable ad.
|
|
317
|
+
* Behavior varies by ad network.
|
|
318
|
+
*
|
|
319
|
+
* @example
|
|
320
|
+
* // Allow user to try again
|
|
321
|
+
* retryButton.onclick = () => sdk.retry();
|
|
322
|
+
*
|
|
323
|
+
* @fires retry When a retry is triggered
|
|
324
|
+
*/
|
|
325
|
+
static retry() {
|
|
326
|
+
if ('mintegral' === AD_NETWORK && isMintegral()) {
|
|
327
|
+
window.gameRetry && window.gameRetry();
|
|
328
|
+
}
|
|
329
|
+
else if ('nucleo' === AD_PROTOCOL && isNucleo()) {
|
|
330
|
+
NUC.trigger.tryAgain();
|
|
331
|
+
}
|
|
332
|
+
emitEvent('retry');
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Triggers the install/download action for the advertised app.
|
|
336
|
+
* Handles different store opening methods across ad networks.
|
|
337
|
+
*
|
|
338
|
+
* @example
|
|
339
|
+
* // Call when user wants to install
|
|
340
|
+
* installButton.onclick = () => sdk.install();
|
|
341
|
+
*
|
|
342
|
+
* @fires finish If the ad hasn't been marked as finished
|
|
343
|
+
* @fires install When the install action is triggered
|
|
344
|
+
*/
|
|
345
|
+
static install() {
|
|
346
|
+
if (!sdk.isFinished) {
|
|
347
|
+
sdk.isFinished = true;
|
|
348
|
+
let timeout = 0;
|
|
349
|
+
if ('tapjoy' === AD_NETWORK && isTapjoy()) {
|
|
350
|
+
finishTapjoy();
|
|
351
|
+
timeout = 300;
|
|
352
|
+
}
|
|
353
|
+
emitEvent('finish');
|
|
354
|
+
setTimeout(function () {
|
|
355
|
+
sdk.install();
|
|
356
|
+
}, timeout);
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
if (isInstallClicked)
|
|
360
|
+
return;
|
|
361
|
+
isInstallClicked = true;
|
|
362
|
+
setTimeout(function () {
|
|
363
|
+
isInstallClicked = false;
|
|
364
|
+
}, 500);
|
|
365
|
+
emitEvent('install');
|
|
366
|
+
if ('mraid' === AD_PROTOCOL && isMraid()) {
|
|
367
|
+
mraid.open(destinationUrl);
|
|
368
|
+
}
|
|
369
|
+
else if ('dapi' === AD_PROTOCOL && isDapi()) {
|
|
370
|
+
dapi.openStoreUrl();
|
|
371
|
+
}
|
|
372
|
+
else if ('nucleo' === AD_PROTOCOL && isNucleo()) {
|
|
373
|
+
NUC.trigger.convert(destinationUrl);
|
|
374
|
+
}
|
|
375
|
+
else if ('facebook' == AD_NETWORK && isFacebook()) {
|
|
376
|
+
FbPlayableAd.onCTAClick();
|
|
377
|
+
}
|
|
378
|
+
else if ('vungle' == AD_NETWORK) {
|
|
379
|
+
parent.postMessage('download', '*');
|
|
380
|
+
}
|
|
381
|
+
else if ('google' == AD_NETWORK && isGoogle()) {
|
|
382
|
+
ExitApi.exit();
|
|
383
|
+
}
|
|
384
|
+
else if ('mintegral' === AD_NETWORK && isMintegral()) {
|
|
385
|
+
window.install && window.install();
|
|
386
|
+
}
|
|
387
|
+
else if ('tapjoy' === AD_NETWORK && isTapjoy()) {
|
|
388
|
+
window.TJ_API.click();
|
|
389
|
+
}
|
|
390
|
+
else if ('tiktok' === AD_NETWORK && isTikTok()) {
|
|
391
|
+
window.openAppStore();
|
|
392
|
+
}
|
|
393
|
+
else {
|
|
394
|
+
window.open(destinationUrl);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Trigger force resize event
|
|
399
|
+
* Useful when container size changes need to be manually propagated.
|
|
400
|
+
*
|
|
401
|
+
* @example
|
|
402
|
+
* sdk.resize();
|
|
403
|
+
*
|
|
404
|
+
* @fires resize With current maxWidth and maxHeight
|
|
405
|
+
*/
|
|
406
|
+
static resize() {
|
|
407
|
+
handleResize(sdk.maxWidth, sdk.maxHeight);
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Forces the playable ad into a paused state.
|
|
411
|
+
*
|
|
412
|
+
* @example
|
|
413
|
+
* // Pause the experience
|
|
414
|
+
* pauseButton.onclick = () => sdk.pause();
|
|
415
|
+
*
|
|
416
|
+
* @fires pause When the ad enters paused state
|
|
417
|
+
*/
|
|
418
|
+
static pause() {
|
|
419
|
+
if (!isForcePaused) {
|
|
420
|
+
isForcePaused = true;
|
|
421
|
+
handlePause();
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Resumes the playable ad from a forced pause state.
|
|
426
|
+
* Only works if the ad was paused via sdk.pause().
|
|
427
|
+
*
|
|
428
|
+
* @example
|
|
429
|
+
* // Resume from pause
|
|
430
|
+
* resumeButton.onclick = () => sdk.resume();
|
|
431
|
+
*
|
|
432
|
+
* @fires resume When the ad resumes from pause
|
|
433
|
+
*/
|
|
434
|
+
static resume() {
|
|
435
|
+
if (isForcePaused) {
|
|
436
|
+
isForcePaused = false;
|
|
437
|
+
handleResume();
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Registers an event listener.
|
|
442
|
+
*
|
|
443
|
+
* @param event Name of the event to listen for
|
|
444
|
+
* @param fn Callback function to execute when event occurs
|
|
445
|
+
* @param context Optional 'this' context for the callback
|
|
446
|
+
*
|
|
447
|
+
* @example
|
|
448
|
+
* // Listen for user interactions
|
|
449
|
+
* sdk.on('interaction', (count) => {
|
|
450
|
+
* console.log(`User interaction #${count}`);
|
|
451
|
+
* });
|
|
452
|
+
*
|
|
453
|
+
* // Listen for resize with context
|
|
454
|
+
* sdk.on('resize', function(width, height) {
|
|
455
|
+
* this.updateLayout(width, height);
|
|
456
|
+
* }, gameInstance);
|
|
457
|
+
*/
|
|
458
|
+
static on(event, fn, context) {
|
|
459
|
+
onEvent(event, fn, context);
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Registers a one-time event listener that removes itself after execution.
|
|
463
|
+
*
|
|
464
|
+
* @param event Name of the event to listen for
|
|
465
|
+
* @param fn Callback function to execute when event occurs
|
|
466
|
+
* @param context Optional 'this' context for the callback
|
|
467
|
+
*
|
|
468
|
+
* @example
|
|
469
|
+
* // Listen for first interaction only
|
|
470
|
+
* sdk.once('interaction', () => {
|
|
471
|
+
* console.log('First user interaction occurred!');
|
|
472
|
+
* });
|
|
473
|
+
*/
|
|
474
|
+
static once(event, fn, context) {
|
|
475
|
+
onEvent(event, fn, context, true);
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Removes an event listener.
|
|
479
|
+
*
|
|
480
|
+
* @param event Name of the event to stop listening for
|
|
481
|
+
* @param fn Optional callback function to remove (if not provided, removes all listeners for the event)
|
|
482
|
+
* @param context Optional 'this' context to match when removing
|
|
483
|
+
*
|
|
484
|
+
* @example
|
|
485
|
+
* // Remove specific listener
|
|
486
|
+
* const handler = () => console.log('Interaction');
|
|
487
|
+
* sdk.off('interaction', handler);
|
|
488
|
+
*
|
|
489
|
+
* // Remove all listeners for an event
|
|
490
|
+
* sdk.off('interaction');
|
|
491
|
+
*/
|
|
492
|
+
static off(event, fn, context) {
|
|
493
|
+
offEvent(event, fn, context);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
/** Current version of the SDK */
|
|
497
|
+
sdk.version = '1.0.1';
|
|
498
|
+
/** Current maximum width of the playable ad container in pixels */
|
|
499
|
+
sdk.maxWidth = Math.floor(window.innerWidth);
|
|
500
|
+
/** Current maximum height of the playable ad container in pixels */
|
|
501
|
+
sdk.maxHeight = Math.floor(window.innerHeight);
|
|
502
|
+
/** Indicates if the current orientation is landscape (width > height) */
|
|
503
|
+
sdk.isLandscape = window.innerWidth > window.innerHeight;
|
|
504
|
+
/** Indicates if the Ad Network is ready and playable ad can be initialized */
|
|
505
|
+
sdk.isReady = false;
|
|
506
|
+
/** Indicates if all playable ad resources are loaded and gameplay has started */
|
|
507
|
+
sdk.isStarted = false;
|
|
508
|
+
/** Indicates if the playable ad is currently paused */
|
|
509
|
+
sdk.isPaused = false;
|
|
510
|
+
/** Indicates if the playable ad has finished */
|
|
511
|
+
sdk.isFinished = false;
|
|
512
|
+
/** Current volume level (0-1) */
|
|
513
|
+
sdk.volume = 1;
|
|
514
|
+
/** Number of user interactions with the playable ad */
|
|
515
|
+
sdk.interactions = 0;
|
|
516
|
+
export { sdk };
|
|
517
|
+
window.PlayableSDK = sdk;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type EventName = 'init' | 'boot' | 'ready' | 'start' | 'interaction' | 'resize' | 'pause' | 'resume' | 'volume' | 'retry' | 'finish' | 'install';
|
|
2
|
+
export declare function onEvent(event: EventName, fn: Function, context?: any, once?: boolean): void;
|
|
3
|
+
export declare function offEvent(event: EventName, fn?: Function, context?: any): void;
|
|
4
|
+
export declare function emitEvent(event: EventName, a1?: any, a2?: any, a3?: any): void;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
const registeredEvents = {};
|
|
2
|
+
export function onEvent(event, fn, context, once) {
|
|
3
|
+
let listeners = registeredEvents[event];
|
|
4
|
+
if (!listeners) {
|
|
5
|
+
listeners = registeredEvents[event] = {
|
|
6
|
+
list: []
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
listeners.list.push(fn, context || null, once || false);
|
|
10
|
+
}
|
|
11
|
+
export function offEvent(event, fn, context) {
|
|
12
|
+
const listeners = registeredEvents[event];
|
|
13
|
+
if (!listeners)
|
|
14
|
+
return;
|
|
15
|
+
var fnArray = listeners.list;
|
|
16
|
+
if (!fn) {
|
|
17
|
+
fnArray.length = 0;
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
let i = fnArray.length;
|
|
21
|
+
while (i > 0) {
|
|
22
|
+
i -= 3;
|
|
23
|
+
if (fnArray[i] == fn && (context !== undefined || fnArray[i + 1] == context)) {
|
|
24
|
+
fnArray.splice(i, 3);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (fnArray.length == 0) {
|
|
29
|
+
delete registeredEvents[event];
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function emitEvent(event, a1, a2, a3) {
|
|
33
|
+
var listeners = registeredEvents[event];
|
|
34
|
+
if (!listeners)
|
|
35
|
+
return;
|
|
36
|
+
const fnArray = listeners.list;
|
|
37
|
+
const len = arguments.length;
|
|
38
|
+
let fn, ctx;
|
|
39
|
+
for (var i = 0; i < fnArray.length; i += 3) {
|
|
40
|
+
fn = fnArray[i];
|
|
41
|
+
ctx = fnArray[i + 1];
|
|
42
|
+
if (fnArray[i + 2]) {
|
|
43
|
+
fnArray.splice(i, 3);
|
|
44
|
+
i -= 3;
|
|
45
|
+
}
|
|
46
|
+
if (len <= 1)
|
|
47
|
+
fn.call(ctx);
|
|
48
|
+
else if (len == 2)
|
|
49
|
+
fn.call(ctx, a1);
|
|
50
|
+
else if (len == 3)
|
|
51
|
+
fn.call(ctx, a1, a2);
|
|
52
|
+
else
|
|
53
|
+
fn.call(ctx, a1, a2, a3);
|
|
54
|
+
}
|
|
55
|
+
if (fnArray.length == 0) {
|
|
56
|
+
delete registeredEvents[event];
|
|
57
|
+
}
|
|
58
|
+
}
|