@68publishers/amp-client
Version:
JS Client for 68publishers/amp
180 lines (135 loc) • 5.86 kB
JavaScript
import { Banner } from '../banner.mjs';
import { Fingerprint } from '../fingerprint.mjs';
import { PositionData } from '../position-data.mjs';
import { AttributesParser } from '../attributes-parser.mjs';
import { Contents } from '../responsive/contents.mjs';
import { evalScripts } from '../../utils/dom-helpers.mjs';
export class ExternalBanner extends Banner {
#fingerprints = [];
#contentsByBannerId = {};
#innerRootElement = null;
constructor(
dimensionsProvider,
eventBus,
uid,
element,
) {
if (!('ampBannerExternal' in element.dataset)) {
throw new Error(`Unable to initialize ExternalBanner from element that does not have an attribute "data-amp-external".`);
}
const externalData = JSON.parse(decodeURIComponent(atob(element.dataset.ampBannerExternal)));
if (!('state' in externalData) || !('positionData' in externalData)) {
throw new Error(`Unable to initialize ExternalBanner data attribute "data-amp-external" is malformed.`);
}
const state = externalData.state;
const positionData = new PositionData(externalData.positionData);
const options = AttributesParser.parseOptions(element);
super(eventBus, uid, element, positionData.code, options);
const fingerprints = [];
const contentsByBannerId = {};
const elementClone = element.cloneNode(true);
const bannerElements = elementClone.querySelectorAll('[data-amp-banner-fingerprint]');
let bannersListElement = bannerElements.item(0)?.parentElement || null;
let innerRootElement = bannersListElement;
if (bannersListElement === elementClone) {
bannersListElement = innerRootElement = null;
} else {
while (null !== innerRootElement && innerRootElement !== elementClone && innerRootElement?.parentElement !== elementClone) {
innerRootElement = innerRootElement.parentElement || null;
}
}
for (let banner of bannerElements) {
const fingerprint = Fingerprint.createFromValue(banner.dataset.ampBannerFingerprint);
fingerprints.push(fingerprint);
for (let content of banner.querySelectorAll('[data-amp-content-breakpoint]')) {
let breakpoint = content.dataset.ampContentBreakpoint;
breakpoint = 'default' === breakpoint ? null : parseInt(breakpoint);
if (!(fingerprint.bannerId in contentsByBannerId)) {
contentsByBannerId[fingerprint.bannerId] = new Contents(dimensionsProvider, positionData.breakpointType);
}
const bannerClone = banner.cloneNode(false);
bannerClone.insertAdjacentElement('afterbegin', content);
contentsByBannerId[fingerprint.bannerId].addContent(breakpoint, {
html: bannerClone.outerHTML,
contentType: content.dataset.ampContentType || 'unknown',
});
}
}
bannersListElement && (bannersListElement.dataset.ampBannerList = 'true');
bannersListElement && (bannersListElement.innerHTML = '');
this._positionData = positionData;
this.#fingerprints = fingerprints;
this.#contentsByBannerId = contentsByBannerId;
this.#innerRootElement = innerRootElement;
this.#redraw(false);
this.setState(state.value, state.info);
}
/**
* @returns {Array<Fingerprint>}
*/
get fingerprints() {
return this.#fingerprints;
}
unsetFingerprint(fingerprint) {
this.#fingerprints = this.#fingerprints.filter(f => f.value !== fingerprint.value);
const bannerId = fingerprint.bannerId;
if (bannerId in this.#contentsByBannerId) {
delete this.#contentsByBannerId[bannerId];
}
if (0 >= this.#fingerprints.length) {
this.setState(this.STATE.CLOSED, 'Banner has empty data.');
}
}
/**
* @returns {number|null}
*/
getCurrentBreakpoint(bannerId) {
const contents = this.#contentsByBannerId[bannerId] || null;
if (null === contents) {
return null;
}
return contents.content?.breakpoint || null;
}
isExternal() {
return true;
}
redrawIfNeeded() {
if (this.#redraw(true)) {
this.setState(this.STATE.RENDERED, 'Banner was successfully redrawn.');
}
}
#redraw(ifNeeded) {
let redraw = !ifNeeded;
if (!redraw) {
for (let bannerId in this.#contentsByBannerId) {
const contents = this.#contentsByBannerId[bannerId];
if (contents.needRedraw()) {
redraw = true;
break;
}
}
}
if (!redraw) {
return false;
}
const banners = [];
for (let bannerId in this.#contentsByBannerId) {
const content = this.#contentsByBannerId[bannerId].content;
if (null !== content && 'noContent' !== content.data.contentType) {
banners.push(content.data.html);
}
}
if (0 >= banners.length) {
this.element.innerHTML = '';
return true;
}
const rootEl = this.#innerRootElement ? this.#innerRootElement.cloneNode(true) : null;
let listEl = null !== rootEl && undefined === rootEl.dataset.ampBannerList ? rootEl.querySelector('[data-amp-banner-list]') : null;
(listEl ?? rootEl ?? this.element).innerHTML = banners.join("\n");
if (null !== rootEl) {
this.element.innerHTML = rootEl.outerHTML;
}
evalScripts(this.element);
return true;
}
}