src/formats/interscroller.js
import { cpexLog, cpexError, addIframe, isMobile } from '../utils.js'
/**
* HTML creative with fixed position relative to scrolling, clipped within a rectangle
*/
export default class Interscroller {
constructor (elementId, adUnit, main, width, height) {
this.main = main
this.type = 'interscroller'
this.adUnit = adUnit
this.elementId = elementId
this.settings = main.settings.formats.interscroller
this.width = width
this.height = height
this.loaded = false
this.iframeCSS = `width: ${this.width}px; height: ${this.height}px` // Needed for HB reRender
this.offset = this.settings.offset || 0
window.addEventListener('resize', () => { this.resize() })
cpexLog('Interscroller: Caught Interscroller custom format, in elementId ' + elementId)
}
/**
* Resizes wrapper to cover full viewport width
*/
resize () {
this.element.style.height = this.finalHeight
if (this.wrapper) {
// Center wrapper based on element's position
const elementRect = this.element.getBoundingClientRect()
this.wrapper.style.setProperty('margin-left', `${-elementRect.left}px`, 'important')
// Zoom iframe
const horizontalAspect = document.documentElement.clientWidth / this.width
const verticalAspect = document.documentElement.clientHeight / this.height
const largestAspect = verticalAspect < horizontalAspect ? verticalAspect : horizontalAspect
this.iframe.style.transform = `scale(${largestAspect}) translateY(${this.offset}px)`
// Center iframe
const wrapperRect = this.wrapper.getBoundingClientRect()
const leftOffset = (wrapperRect.width - this.width) / 2
this.iframe.style.left = leftOffset + 'px'
}
}
/**
* Places the interscroller container into the page
*/
renderIframe () {
// Add CSS rule
const style = document.createElement('style')
document.head.appendChild(style)
style.sheet.insertRule('@keyframes ios-clip-hack { from { top: 0 } to { top: 0.01px }; }')
style.sheet.insertRule('div.cpex-interscroller-wrapper { position: absolute; top: 0px; left: 0px; width: 100vw; height: 100%; clip: rect(0px, auto, auto, 0px); }')
style.sheet.insertRule('iframe.cpex-interscroller-iframe { position: fixed; top: 0px; margin: auto; display: block; border: none; animation: ios-clip-hack .1s infinite; max-width: initial; }')
// Set interscroller height on the target element
this.element = document.getElementById(this.elementId)
if (this.element) {
this.originalHeight = this.element.style.height
this.finalHeight = typeof this.settings !== 'undefined' && this.settings.height ? this.settings.height : '75vh'
this.element.style.position = 'relative'
this.element.style.height = this.finalHeight
// Add wrapper element
this.wrapper = document.createElement('div')
this.wrapper.classList.add('cpex-interscroller-wrapper')
this.element.appendChild(this.wrapper)
// Add ad iframe
this.iframe = addIframe(this.wrapper, { id: this.elementId + '-iframe' }, (iframe) => { // onload callback
this.loaded = true
cpexLog('Interscroller: Rendered into ', this.elementId)
})
this.iframe.classList.add('cpex-interscroller-iframe')
this.iframe.style.cssText = this.iframeCSS
if (isMobile) { this.iframe.style.transformOrigin = '50% 0' } // there is a weird top offset on mobile devices otherwise
setTimeout(() => { // giving some time to the page element to render, in case it's injected into the page
this.resize()
}, 0)
return this.iframe
} else {
cpexError(`Interscroller: Target element '${this.elementId}' not found`)
}
}
/**
* Returns the page to its original state
*/
reset () {
this.wrapper.remove()
this.element.style.height = this.originalHeight
const ads = window.cpexPackage.customAds
if (ads) { delete ads[this.elementId] }
}
}