///
import { IProvider } from './ad-provider'
import { AdType, AdEvents, H5AdWrapper } from '../h5-ad-wrapper'
enum GoogleAdEvent {
start,
firstQuartile,
midPoint,
thirdQuartile,
complete
}
export interface ICustomParams {
[name: string]: string | number | any[]
}
export class Ima3 implements IProvider {
private gameContent: any
private adContent!: HTMLElement
private adDisplay!: GoogleAds.ima.AdDisplayContainer
private adLoader!: GoogleAds.ima.AdsLoader
private adsManager!: GoogleAds.ima.AdsManager
private googleEnabled: boolean = false
public adsEnabled: boolean = true
private adTagUrl: string = ''
private adRequested: boolean = false
public adManager!: H5AdWrapper
private resizeListener!: () => void
constructor(canvas: HTMLCanvasElement, adTagUrl: string) {
this.areAdsEnabled()
if (typeof google === 'undefined') {
return
}
this.googleEnabled = true
this.gameContent =
typeof canvas.parentElement === 'string'
? document.getElementById(canvas.parentElement as string)
: canvas.parentElement
// this.gameContent.currentTime = 100;
this.gameContent.style.position = 'absolute'
this.gameContent.style.width = '100%'
this.adContent = this.gameContent.parentNode.appendChild(document.createElement('div'))
this.adContent.id = 'phaser-ad-container'
this.adContent.style.position = 'absolute'
this.adContent.style.zIndex = '9999'
this.adContent.style.display = 'none'
this.adContent.style.top = '0'
this.adContent.style.left = '0'
this.adContent.style.width = '100%'
this.adContent.style.height = '100%'
this.adContent.style.overflow = 'hidden'
this.adTagUrl = adTagUrl
// Create the ad display container.
this.adDisplay = new google.ima.AdDisplayContainer(this.adContent)
// Set vpaid enabled, and update locale
;(google.ima.settings as any).setVpaidMode(
(google.ima as any).ImaSdkSettings.VpaidMode.ENABLED
)
;(google.ima.settings as any).setLocale('nl')
// Create ads loader, and register events
this.adLoader = new google.ima.AdsLoader(this.adDisplay)
this.adLoader.addEventListener(
google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,
this.onAdManagerLoader,
false,
this
)
this.adLoader.addEventListener(
google.ima.AdErrorEvent.Type.AD_ERROR,
this.onAdError,
false,
this
)
}
public setManager(manager: H5AdWrapper): void {
this.adManager = manager
this.adManager.emit(AdEvents.AD_PROVIDER_LOADED)
}
/**
* Doing an ad request, if anything is wrong with the lib (missing ima3, failed request) we just dispatch the contentResumed event
* Otherwise we display an ad
*/
public showAd(adType: AdType, customParams?: ICustomParams): void {
console.log('Ad Requested')
if (this.adRequested) {
return
}
if (!this.adsEnabled) {
this.adManager.emit(AdEvents.AD_DISABLED, true)
}
if (!this.googleEnabled) {
this.onContentResumeRequested()
return
}
// For mobile this ad request needs to be handled post user click
this.adDisplay.initialize()
// Request video ads.
let adsRequest: GoogleAds.ima.AdsRequest = new google.ima.AdsRequest()
adsRequest.adTagUrl = this.adTagUrl + this.parseCustomParams(customParams)
let width: number = window.innerWidth // parseInt((!this.game.canvas.style.width ? this.game.canvas.width : this.game.canvas.style.width), 10);
let height: number = window.innerHeight // parseInt((!this.game.canvas.style.height ? this.game.canvas.height : this.game.canvas.style.height), 10);
// Here we check if phaser is fullscreen or not, if we are fullscreen, we subtract some of the width and height, to counter for the resize (
// Fullscreen should be disabled for the ad, (onContentPaused) and requested for again when the game resumes
if (document.body.clientHeight < window.innerHeight) {
height = document.body.clientHeight
width = document.body.clientWidth
}
// Specify the linear and nonlinear slot sizes. This helps the SDK to
// select the correct creative if multiple are returned.
adsRequest.linearAdSlotWidth = width
adsRequest.linearAdSlotHeight = height
adsRequest.nonLinearAdSlotWidth = width
adsRequest.nonLinearAdSlotHeight = height
// Required for games, see:
// http://googleadsdeveloper.blogspot.nl/2015/10/important-changes-for-gaming-publishers.html
adsRequest.forceNonLinearFullSlot = true
try {
this.adRequested = true
this.adLoader.requestAds(adsRequest)
} catch (e) {
console.log(e)
this.onContentResumeRequested()
}
}
public adAvailable(adType: AdType): boolean {
return true
}
// Does nothing, but needed for Provider interface
public preloadAd(): void {
return
}
// Does nothing, but needed for Provider interface
public destroyAd(): void {
return
}
// Does nothing, but needed for Provider interface
public hideAd(): void {
return
}
/**
* Called when the ads manager was loaded.
* We register all ad related events here, and initialize the manager with the game width/height
*
* @param adsManagerLoadedEvent
*/
private onAdManagerLoader(adsManagerLoadedEvent: GoogleAds.ima.AdsManagerLoadedEvent): void {
console.log('AdsManager loaded')
// Get the ads manager.
let adsRenderingSettings: GoogleAds.ima.AdsRenderingSettings = new google.ima.AdsRenderingSettings()
adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true
// videoContent should be set to the content video element.
let adsManager: GoogleAds.ima.AdsManager = adsManagerLoadedEvent.getAdsManager(
this.gameContent,
adsRenderingSettings
)
this.adsManager = adsManager
console.log(adsManager.isCustomClickTrackingUsed())
// Add listeners to the required events.
adsManager.addEventListener(
google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED,
this.onContentPauseRequested,
false,
this
)
adsManager.addEventListener(
google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED,
this.onContentResumeRequested,
false,
this
)
adsManager.addEventListener(
google.ima.AdErrorEvent.Type.AD_ERROR,
this.onAdError,
false,
this
)
;[
google.ima.AdEvent.Type.ALL_ADS_COMPLETED,
google.ima.AdEvent.Type.CLICK,
google.ima.AdEvent.Type.COMPLETE,
google.ima.AdEvent.Type.FIRST_QUARTILE,
google.ima.AdEvent.Type.LOADED,
google.ima.AdEvent.Type.MIDPOINT,
google.ima.AdEvent.Type.PAUSED,
google.ima.AdEvent.Type.STARTED,
google.ima.AdEvent.Type.THIRD_QUARTILE
].forEach((event: string) => {
adsManager.addEventListener(event, this.onAdEvent, false, this)
})
try {
// Show the ad elements, we only need to show the faux videoelement on iOS, because the ad is displayed in there.
this.adContent.style.display = 'block'
// Initialize the ads manager. Ad rules playlist will start at this time.
let width: number = window.innerWidth // parseInt((!this.game.canvas.style.width ? this.game.canvas.width : this.game.canvas.style.width), 10);
let height: number = window.innerHeight // parseInt((!this.game.canvas.style.height ? this.game.canvas.height : this.game.canvas.style.height), 10);
this.adsManager.init(width, height, google.ima.ViewMode.NORMAL)
// Call play to start showing the ad. Single video and overlay ads will
// start at this time; the call will be ignored for ad rules.
this.adsManager.start()
this.resizeListener = () => {
if (this.adsManager === null) {
return
}
// Window was resized, so expect something similar
console.log('Resizing ad size')
this.adsManager.resize(
window.innerWidth,
window.innerHeight,
google.ima.ViewMode.NORMAL
)
}
window.addEventListener('resize', this.resizeListener)
} catch (adError) {
console.log('Adsmanager error:', adError)
this.onAdError(adError)
}
}
/**
* Generic ad events are handled here
* @param adEvent
*/
private onAdEvent(adEvent: any): void {
console.log('onAdEvent', adEvent)
switch (adEvent.type) {
case google.ima.AdEvent.Type.CLICK:
this.adManager.emit(AdEvents.AD_CLICKED)
break
case google.ima.AdEvent.Type.LOADED:
this.adRequested = false
let ad: any = adEvent.getAd()
console.log('is ad linear?', ad.isLinear())
if (!ad.isLinear()) {
this.onContentResumeRequested()
}
break
case google.ima.AdEvent.Type.STARTED:
this.adManager.emit(AdEvents.AD_PROGRESSION, GoogleAdEvent.start)
break
case google.ima.AdEvent.Type.FIRST_QUARTILE:
this.adManager.emit(AdEvents.AD_PROGRESSION, GoogleAdEvent.firstQuartile)
break
case google.ima.AdEvent.Type.MIDPOINT:
this.adManager.emit(AdEvents.AD_PROGRESSION, GoogleAdEvent.midPoint)
break
case google.ima.AdEvent.Type.THIRD_QUARTILE:
this.adManager.emit(AdEvents.AD_PROGRESSION, GoogleAdEvent.thirdQuartile)
break
case google.ima.AdEvent.Type.COMPLETE:
this.adManager.emit(AdEvents.AD_PROGRESSION, GoogleAdEvent.complete)
break
case google.ima.AdEvent.Type.ALL_ADS_COMPLETED:
this.onContentResumeRequested()
break
}
}
private onAdError(error: any): void {
console.log('gneric ad error', error)
if (null !== this.adsManager) {
this.adsManager.destroy()
if (null !== this.resizeListener) {
window.removeEventListener('resize', this.resizeListener)
}
}
if (this.adRequested) {
this.adRequested = false
}
// We silently ignore adLoader errors, it just means there is no ad available
this.onContentResumeRequested()
}
/**
* When the ad starts playing, and the game should be paused
*/
private onContentPauseRequested(): void {
console.log('onContentPauseRequested', arguments)
this.adManager.emit(AdEvents.CONTENT_PAUSED)
}
/**
* When the ad is finished and the game should be resumed
*/
private onContentResumeRequested(): void {
console.log('onContentResumeRequested', arguments)
if (typeof google === 'undefined') {
this.adManager.emit(AdEvents.CONTENT_RESUMED)
return
}
this.adContent.style.display = 'none'
this.adManager.emit(AdEvents.CONTENT_RESUMED)
}
private parseCustomParams(customParams: ICustomParams | undefined): string {
if (undefined !== customParams) {
let customDataString: string = ''
for (let key in customParams) {
if (customParams.hasOwnProperty(key)) {
if (customDataString.length > 0) {
customDataString += '' + '&'
}
let param: any = Array.isArray(customParams[key])
? (customParams[key] as any[]).join(',')
: customParams[key]
customDataString += key + '=' + param
}
}
return '&cust_params=' + encodeURIComponent(customDataString)
}
return ''
}
/**
* Checks if the ads are enabled (e.g; adblock is enabled or not)
* @returns {boolean}
*/
private areAdsEnabled(): void {
let test: HTMLElement = document.createElement('div')
test.innerHTML = ' '
test.className = 'adsbox'
test.style.position = 'absolute'
test.style.fontSize = '10px'
document.body.appendChild(test)
// let adsEnabled: boolean;
let isEnabled: () => boolean = () => {
let enabled: boolean = true
if (test.offsetHeight === 0) {
enabled = false
}
if (test.parentNode) {
test.parentNode.removeChild(test)
}
return enabled
}
window.setTimeout(() => {
this.adsEnabled = isEnabled()
}, 100)
}
}