UNPKG

@68publishers/amp-client

Version:

JS Client for 68publishers/amp

190 lines (154 loc) 5.56 kB
import { ManagedBanner } from './managed/managed-banner.mjs'; import { ExternalBanner } from './external/external-banner.mjs'; import { EmbedBanner } from './embed/embed-banner.mjs'; import { Banner } from './banner.mjs'; import { State } from './state.mjs'; import { Fingerprint } from './fingerprint.mjs'; import { SequenceGenerator } from '../utils/sequence-generator.mjs'; import { Events } from '../event/events.mjs'; import { getHtmlElement } from '../utils/dom-helpers.mjs'; export class BannerManager { #eventBus; #dimensionsProvider; #bannerRenderer; #sequenceGenerator; #banners = []; #mutationObserver; /** * @param {EventBus} eventBus * @param {DimensionsProvider} dimensionsProvider * @param {BannerRenderer|null} bannerRenderer */ constructor( eventBus, dimensionsProvider, bannerRenderer = null, ) { this.#eventBus = eventBus; this.#dimensionsProvider = dimensionsProvider; this.#bannerRenderer = bannerRenderer; this.#sequenceGenerator = new SequenceGenerator(); this.#mutationObserver = new MutationObserver((mutationList) => { for (const mutation of mutationList) { if (!(mutation.target instanceof HTMLElement)) { continue; } const uid = mutation.target.closest('[data-amp-attached]')?.dataset?.ampAttached; const banner = undefined !== uid ? this.getBannerByUid(parseInt(uid)) : null; if (banner) { this.#eventBus.dispatch(Events.ON_BANNER_MUTATED, { banner, mutation }); } } }); this.STATE = State; } addExternalBanner(element, refWindow = window) { element = getHtmlElement(element, refWindow); const uid = this.#sequenceGenerator.getNextIdentifier(); element.setAttribute('data-amp-attached', uid); const banner = new ExternalBanner( this.#dimensionsProvider, this.#eventBus, uid, element, ); this.#observeMutations(element); this.#banners.push(banner); return banner; } addManagedBanner(element, position, resources = {}, options = {}, refWindow = window) { if (null === this.#bannerRenderer) { throw new Error(`Unable to add managed banner, renderer is not provided.`); } element = getHtmlElement(element, refWindow); const uid = this.#sequenceGenerator.getNextIdentifier(); element.setAttribute('data-amp-attached', uid); const banner = new ManagedBanner( this.#dimensionsProvider, this.#bannerRenderer, this.#eventBus, uid, element, position, resources, options, ); this.#observeMutations(element); this.#banners.push(banner); return banner; } addEmbedBanner(element, iframe, position, options) { element = getHtmlElement(element, window); iframe = getHtmlElement(iframe, window); const uid = this.#sequenceGenerator.getNextIdentifier(); element.setAttribute('data-amp-attached', uid); const banner = new EmbedBanner( this.#eventBus, uid, element, iframe, position, options, ); this.#observeMutations(element); this.#banners.push(banner); return banner; } removeBanner(banner) { const length = this.#banners.length; this.#banners = this.#banners.filter(b => b !== banner); return length !== this.#banners.length; } getBannersByState({state, managed = true, external = true, embed = true}) { return this.#banners.filter(banner => { if (!(banner instanceof Banner) || banner.state !== state) { return false; } return !((banner instanceof ManagedBanner && !managed) || (banner instanceof ExternalBanner && !external) || (banner instanceof EmbedBanner && !embed)); }); } getBannerByFingerprint(fingerprint) { const fingerprintValue = fingerprint instanceof Fingerprint ? fingerprint.value : fingerprint; for (let banner of this.#banners) { if (banner instanceof EmbedBanner) { continue; } for (let ft of banner.fingerprints) { if (ft.value === fingerprintValue) { return banner; } } } return null; } getBannerByUid(uid) { for (let banner of this.#banners) { if (banner.uid === uid) { return banner; } } return null; } getBannerByPosition(positionCode) { for (let banner of this.#banners) { if (banner.position === positionCode) { return banner; } } return null; } #observeMutations(element) { if (!element._ampBannerMutationsObserved) { this.#mutationObserver.observe(element, { subtree: true, childList: true, characterData: false, attributes: true, attributeFilter: [ 'data-amp-banner-close', ], }); element._ampBannerMutationsObserved = true; } } }