///
import { IProvider } from './ad-provider'
import { AdEvents, AdType, H5AdWrapper } from '../h5-ad-wrapper'
enum GameDistributionAdType {
interstitial = 'interstitial',
rewarded = 'rewarded',
display = 'display'
}
export enum GameDistributionBannerSize {
LargeRectangle, // 336x280
MediumRectangle, // 300x250
Billboard, // 970x250
Leaderboard, // 728x90
Skyscraper, // 120x600
WideSkyscraper // 160x600
}
export enum GameDistributionAlignment {
TopLeft,
TopCenter,
TopRight,
CenterLeft,
Center,
CenterRight,
BottomLeft,
BottomCenter,
BottomRight
}
export class GameDistributionBanner {
public element: HTMLElement
private resizeListener!: () => void
private parent!: HTMLElement
private alignment!: GameDistributionAlignment
private width!: number
private height!: number
private scaleFactor: number = 1
private offsetX: number = 0
private offsetY: number = 0
constructor() {
this.element = document.createElement('div')
this.element.style.position = 'absolute'
this.element.style.top = `0px`
this.element.style.left = `0px`
this.element.id = `banner-${Date.now()}${(Math.random() * 10000000) | 0}`
document.body.appendChild(this.element)
}
public loadBanner(): Promise {
if (typeof gdsdk === 'undefined') {
return Promise.reject('GD Sdk not available, probably due to adblocker')
}
return gdsdk.showAd(GameDistributionAdType.display, {
containerId: this.element.id
})
}
public destroy(): void {
document.body.removeChild(this.element)
if (this.resizeListener) {
window.removeEventListener('resize', this.resizeListener)
}
delete this.element
delete this.parent
delete this.alignment
}
public alignIn(element: HTMLElement, position: GameDistributionAlignment): void {
if (this.parent) {
console.warn('Banner already aligned, ignoring...')
return
}
this.parent = element
this.alignment = position
this.resizeListener = () => this.resize()
window.addEventListener('resize', this.resizeListener)
this.resize()
}
public setOffset(x: number = 0, y: number = 0): void {
this.offsetX = x
this.offsetY = y
this.resize()
}
private resize(): void {
if (!this.parent) {
return
}
const parentBoundingRect: ClientRect = this.parent.getBoundingClientRect()
switch (this.alignment) {
case GameDistributionAlignment.TopLeft:
this.position(parentBoundingRect.left, parentBoundingRect.top)
break
case GameDistributionAlignment.TopCenter:
this.position(
parentBoundingRect.left +
parentBoundingRect.width / 2 -
(this.width * this.scaleFactor) / 2,
parentBoundingRect.top
)
break
case GameDistributionAlignment.TopRight:
this.position(
parentBoundingRect.left +
parentBoundingRect.width -
this.width * this.scaleFactor,
parentBoundingRect.top
)
break
case GameDistributionAlignment.CenterLeft:
this.position(
parentBoundingRect.left,
parentBoundingRect.top +
parentBoundingRect.height / 2 -
(this.height * this.scaleFactor) / 2
)
break
case GameDistributionAlignment.Center:
this.position(
parentBoundingRect.left +
parentBoundingRect.width / 2 -
(this.width * this.scaleFactor) / 2,
parentBoundingRect.top +
parentBoundingRect.height / 2 -
(this.height * this.scaleFactor) / 2
)
break
case GameDistributionAlignment.CenterRight:
this.position(
parentBoundingRect.left +
parentBoundingRect.width -
this.width * this.scaleFactor,
parentBoundingRect.top +
parentBoundingRect.height / 2 -
(this.height * this.scaleFactor) / 2
)
break
case GameDistributionAlignment.BottomLeft:
this.position(
parentBoundingRect.left,
parentBoundingRect.top +
parentBoundingRect.height -
this.height * this.scaleFactor
)
break
case GameDistributionAlignment.BottomCenter:
this.position(
parentBoundingRect.left +
parentBoundingRect.width / 2 -
(this.width * this.scaleFactor) / 2,
parentBoundingRect.top +
parentBoundingRect.height -
this.height * this.scaleFactor
)
break
case GameDistributionAlignment.BottomRight:
this.position(
parentBoundingRect.left +
parentBoundingRect.width -
this.width * this.scaleFactor,
parentBoundingRect.top +
parentBoundingRect.height -
this.height * this.scaleFactor
)
break
}
}
public setSize(size: GameDistributionBannerSize): void {
let width: number
let height: number
switch (size) {
default:
case GameDistributionBannerSize.LargeRectangle:
width = 336
height = 280
break
case GameDistributionBannerSize.MediumRectangle:
width = 300
height = 250
break
case GameDistributionBannerSize.Billboard:
width = 970
height = 250
break
case GameDistributionBannerSize.Leaderboard:
width = 728
height = 90
break
case GameDistributionBannerSize.Skyscraper:
width = 120
height = 600
break
case GameDistributionBannerSize.WideSkyscraper:
width = 160
height = 600
break
}
this.width = width
this.height = height
this.element.style.width = `${width}px`
this.element.style.height = `${height}px`
}
public position(x: number, y: number): void {
this.element.style.left = `${x + this.offsetX}px`
this.element.style.top = `${y + this.offsetY}px`
}
public scale(factor: number): void {
this.element.style.transformOrigin = 'left top'
this.scaleFactor = factor
this.element.style.transform = `scale(${factor})`
}
}
export class GameDistribution implements IProvider {
public adManager!: H5AdWrapper
public adsEnabled: boolean = false
public hasRewarded: boolean = false
public adShowing: boolean = false
constructor(gameId: string) {
;(window as any).GD_OPTIONS = {
gameId: gameId,
advertisementSettings: {
autoplay: false
},
onEvent: (event: any) => {
switch (event.name as string) {
case 'SDK_GAME_PAUSE':
// pause game logic / mute audio
this.adManager.emit(AdEvents.CONTENT_PAUSED)
break
case 'SDK_READY':
this.sdkLoaded()
break
default:
break
}
}
} as IGameDistributionSettings
//Include script. even when adblock is enabled, this script also allows us to track our users;
;(function(d: Document, s: string, id: string): void {
let js: HTMLScriptElement
let fjs: HTMLScriptElement = d.getElementsByTagName(s)[0]
if (d.getElementById(id)) {
return
}
js = d.createElement(s)
js.id = id
js.src = '//html5.api.gamedistribution.com/main.min.js'
if (fjs.parentNode) {
fjs.parentNode.insertBefore(js, fjs)
}
})(document, 'script', 'gamedistribution-jssdk')
}
public setManager(manager: H5AdWrapper): void {
this.adManager = manager
this.adManager.emit(AdEvents.AD_PROVIDER_LOADED)
}
private sdkLoaded(): void {
this.adsEnabled = true
}
public showAd(adType: AdType): void {
if (!this.adsEnabled) {
this.adManager.emit(AdEvents.CONTENT_RESUMED)
} else {
if (typeof gdsdk === 'undefined' || (gdsdk && typeof gdsdk.showAd === 'undefined')) {
//So gdsdk isn't available OR
//gdsdk is available, but showBanner is not there (weird but can happen)
this.adsEnabled = false
this.adManager.emit(AdEvents.CONTENT_RESUMED)
return
}
gdsdk
.showAd(
adType === AdType.rewarded
? GameDistributionAdType.rewarded
: GameDistributionAdType.interstitial
)
.then(() => {
if (adType === AdType.rewarded) {
this.adManager.emit(AdEvents.AD_REWARDED)
this.hasRewarded = false
}
this.adManager.emit(AdEvents.CONTENT_RESUMED)
})
.catch(() => {
if (adType === AdType.rewarded && this.hasRewarded) {
this.hasRewarded = false
}
this.adManager.emit(AdEvents.CONTENT_RESUMED)
})
}
}
public createBanner(size: GameDistributionBannerSize): GameDistributionBanner | undefined {
if (!this.adsEnabled) {
return
}
const banner: GameDistributionBanner = new GameDistributionBanner()
banner.setSize(size)
return banner
}
public loadBanner(size: GameDistributionBannerSize): GameDistributionBanner | undefined {
if (!this.adsEnabled) {
return
}
const banner: GameDistributionBanner = new GameDistributionBanner()
banner.setSize(size)
banner.loadBanner()
return banner
}
//Does nothing, but needed for Provider interface
public preloadAd(adType: AdType): void {
if (this.hasRewarded || !this.adsEnabled || adType !== AdType.rewarded) {
return
}
console.log('preloading ad')
gdsdk.preloadAd(GameDistributionAdType.rewarded).then(() => {
this.hasRewarded = true
this.adManager.emit(AdEvents.AD_LOADED, adType)
})
}
public adAvailable(adType: AdType): boolean {
if (adType === AdType.rewarded) {
return this.hasRewarded
}
return true
}
//Does nothing, but needed for Provider interface
public destroyAd(): void {
return
}
//Does nothing, but needed for Provider interface
public hideAd(): void {
return
}
/**
* Checks if the ads are enabled (e.g; adblock is enabled or not)
* @returns {boolean}
*/
private areAdsEnabled(): Promise {
let test: any = document.createElement('script')
test.id = 'debug-test-ad'
test.src = 'https://storage.googleapis.com/cdn.fbrq.io/anyad.js'
document.body.appendChild(test)
// let adsEnabled: boolean;
let isEnabled: () => boolean = () => {
let enabled: boolean = true
if (!document.getElementById('az-test-ad')) {
enabled = false
}
if (document.getElementById('debug-test-ad')) {
let d: any = document.getElementById('debug-test-ad')
try {
d.parentNode.removeChild(d)
} catch (e) {
console.log('cannot remove div')
}
}
if (document.getElementById('az-test-ad')) {
let t: any = document.getElementById('az-test-ad')
try {
t.parentNode.removeChild(t)
} catch (e) {
console.log('cannot remove div')
}
}
return enabled
}
return new Promise(resolve => {
window.setTimeout(() => {
resolve(isEnabled())
}, 100)
})
}
}