src/formats/skin.js
import { cpexError, cpexLog, isDOMObject, addIframe, addStyle, isObject } from '../utils.js'
/**
* HTML creative rendered to the page background
*/
export default class Skin {
constructor (elementId, adUnit, main, width, height) {
this.main = main
this.type = 'skin'
this.adUnit = adUnit
this.elementId = elementId
this.settings = main.settings.formats.skin
this.width = width
this.height = height
this.loaded = false
this.hidden = []
this.offset = 0
this.iframeCSS = `width: ${width}px; height: ${height}px; border:none; display:block; overflow:hidden; margin-left: 50%; transform: translateX(-50%); max-width: initial; ` // Needed here for HB reRender
cpexLog('Skin: Caught Skin custom format, in elementId ' + elementId)
}
/**
* Places the skin container in the page background and styles the page content
*/
renderIframe () {
// Handle settings
if (!this.validateSettings(this.settings)) { return cpexError('Skin: Incorrect skin settings: ' + JSON.stringify(this.settings)) }
// Temporary: Simplify after moving all settings to function selectors (backgroundEl = this.settings.backgroundEl() || document.body)
this.backgroundEl = (typeof this.settings.backgroundEl === 'function' ? this.settings.backgroundEl() : this.settings.backgroundEl) || document.body
this.contentEl = typeof this.settings.contentEl === 'function' ? this.settings.contentEl() : this.settings.contentEl
// Save original style and hide things, based on settings
if (isDOMObject(this.contentEl)) { this.contentStyleBackup = window.getComputedStyle(this.contentEl) }
// Add general temporary CSS
if (this.settings.generalCSS) {
this.generalCSSEl = addStyle(document, this.settings.generalCSS)
}
// Hide obtrusive elements
if (Array.isArray(this.settings.hide) && this.settings.hide.length > 0) {
this.settings.hide.forEach(el => {
const hideEl = typeof el === 'function' ? el() : el
if (isDOMObject(hideEl)) {
this.hidden.push({ element: hideEl, display: hideEl.style.display })
hideEl.style.setProperty('display', 'none', 'important')
}
})
}
// Add wrapper element
this.element = document.createElement('div')
this.element.id = 'cpex-skin'
this.getOffset()
this.element.style.cssText = `position: fixed; top: ${this.offset}px; left: 0px; width: 100%; ${typeof this.settings.zIndex === 'number' ? 'z-index:' + this.settings.zIndex : ''};`
this.backgroundEl.prepend(this.element)
// Label the original element as moved, mainly for debug tag rendering
const targetEl = document.getElementById(this.elementId)
if (targetEl) { targetEl.setAttribute('data-target-id-moved', this.element.id) }
// Style content
if (this.contentEl) { this.contentEl.style.cssText = this.settings.contentCSS }
// Add iframe
this.iframe = addIframe(this.element, { id: this.elementId + '-iframe' }, (iframe) => { // onload callback
this.loaded = true
cpexLog('Skin: Rendered into ', this.backgroundEl)
})
this.iframe.style.cssText = this.iframeCSS
// Register scrolling offset
if (this.settings.offset && this.settings.offsetScroll) {
this.updateOffset()
window.addEventListener('scroll', () => { this.updateOffset() })
}
return this.iframe
}
getOffset () {
if (typeof this.settings.offset === 'function') {
this.offset = this.settings.offset()
} else if (typeof this.settings.offset === 'number') {
this.offset = this.settings.offset
}
}
updateOffset () {
this.element.style.top = window.scrollY < this.offset ? this.offset - window.scrollY + 'px' : '0px'
}
/**
* Returns the page to its original state
*/
reset () {
this.element.remove()
if (this.contentEl) { this.contentEl.style = this.contentStyleBackup }
if (this.generalCSSEl) {
this.generalCSSEl.remove()
delete this.generalCSSEl
}
this.hidden.forEach(item => { item.element.style.display = item.display })
const ads = window.cpexPackage.customAds
if (ads) { delete ads[this.elementId] }
}
/**
* Check skin settings if they contain html elements
*/
validateSettings (settings) {
return isObject(settings)
}
}