@shopgate/pwa-common
Version:
Common library for the Shopgate Connect PWA.
194 lines (175 loc) • 7.34 kB
JavaScript
import { i18n, logger } from '@shopgate/engage/core/helpers';
import { PRIVACY_SETTINGS_PATTERN } from '@shopgate/engage/tracking/constants';
import { isRelativePosition, isAbsolutePosition } from "../../helpers/dom";
import styles from "./style";
const consentMessageIcon = `
<svg
width="100%"
height="100%"
viewBox="0 0 110 84"
version="1.1"
class="${styles.consentIcon}"
xmlns="http://www.w3.org/2000/svg"
>
<g transform="matrix(1,0,0,1,-24.6099,-41.8178)">
<path d="M50.303,68.639L104.088,98.668L56.288,125.172C55.039,125.865 53.518,125.845 52.288,125.12C51.058,124.396 50.303,123.075 50.303,121.648L50.303,68.639ZM50.303,54.702L50.303,45.855C50.303,44.425 51.059,43.102 52.292,42.376C53.524,41.651 55.048,41.631 56.298,42.324C71.141,50.554 109.492,71.82 124.676,80.239C125.95,80.945 126.741,82.288 126.741,83.745C126.741,85.203 125.95,86.545 124.676,87.252L116.612,91.724L50.303,54.702Z" />
<g transform="matrix(0.944597,0.527391,-0.487489,0.873129,45.7069,-42.8282)">
<path d="M139,89C139,87.344 137.757,86 136.227,86L26.773,86C25.243,86 24,87.344 24,89C24,90.656 25.243,92 26.773,92L136.227,92C137.757,92 139,90.656 139,89Z" />
</g>
</g>
</svg>`;
/* eslint-disable class-methods-use-this */
/**
* The MediaProvider base class.
*/
let MediaProvider = /*#__PURE__*/function () {
/**
* Constructor.
* @param {Object} options The provider options.
* @param {boolean} [options.responsify=true] Whether to responsify the video containers.
*/
function MediaProvider(options) {
this.containers = new Map();
this.isPending = false;
this.remoteScriptUrl = null;
this.options = {
responsify: options?.responsify ?? true
};
}
/**
* Callback for when Provider script is loaded
* @callback
* @abstract
*/
var _proto = MediaProvider.prototype;
_proto.onScriptLoaded = function onScriptLoaded() {
logger.error('MediaProvider.onScriptLoaded() needs to be implemented within an inheriting class');
}
/**
* Callback to retrieve a list of media containers
* @callback
* @abstract
*/;
_proto.getMediaContainers = function getMediaContainers() {
logger.error('MediaProvider.getMediaContainers() needs to be implemented within an inheriting class');
}
/**
* Applies optimizations to embedded media iframes within the given container.
* Common enhancements include adding responsive wrappers and appropriate
* sandbox attributes to improve security and layout behavior.
*
* @param {Document} document - The DOM document containing iframes to optimize.
* @returns {MediaProvider}
*/;
_proto.applyIframeOptimizations = function applyIframeOptimizations() {
return this;
}
/**
* Optimizes video container to make it responsive.
* @param {Element} container A DOM container.
* @returns {MediaProvider}
*/;
_proto.responsify = function responsify(container) {
// Do not proceed when video responsify is disabled.
if (!this.options.responsify) return this;
// Remove fixed dimensions from the container.
container.removeAttribute('height');
container.removeAttribute('width');
if (isRelativePosition(container.parentNode) && isAbsolutePosition(container)) {
// Assume responsive embed code
container.parentNode.removeAttribute('style');
}
// Create the wrapper and apply styling.
const wrapper = document.createElement('div');
wrapper.className = styles.responsiveContainer;
// Add the wrapper right before the container into the DOM.
container.parentNode.insertBefore(wrapper, container);
// Move the container into the wrapper.
wrapper.appendChild(container);
return this;
}
/**
* Searches for embedded media and replaces it with a placeholder element when comfort cookie
* consent is not accepted.
*
* Should be called before media container / markup is mounted to the DOM.
* @param {ParentNode} container A DOM container.
* @param {Object} [cookieConsentSettings] Additional settings related to cookie consent.
* @param {boolean} [cookieConsentSettings.comfortCookiesAccepted] Whether comfort cookies
* are accepted.
* @param {boolean} [cookieConsentSettings.statisticsCookiesAccepted] Whether statistics cookies
* are accepted.
* @returns {MediaProvider}
*/;
_proto.handleCookieConsent = function handleCookieConsent(container, cookieConsentSettings = {}) {
const iframes = this.getMediaContainers(container);
if (!iframes.length || cookieConsentSettings.comfortCookiesAccepted !== false) {
return this;
}
iframes.forEach(iframe => {
// Add responsive container around iframes
this.responsify(iframe);
// Select the container and clear its content
const responsiveContainer = iframe.parentNode;
responsiveContainer.textContent = null;
// Add the consent message element to the container
this.injectCookieConsentMessage(responsiveContainer);
});
return this;
}
/**
* Injects a cookie consent message element into a container
* @param {Element} container A DOM container.
* @returns {MediaProvider}
*/;
_proto.injectCookieConsentMessage = function injectCookieConsentMessage(container) {
// Create the wrapper for the message element
const messageWrapper = document.createElement('div');
messageWrapper.classList.add(styles.consentContainer, 'common__media-provider_cookie-consent-message-container');
// Add an SVG icon (implemented this way, since there where issues with document.createElement)
messageWrapper.innerHTML = consentMessageIcon;
// Create the main message and add it to the wrapper
const message = document.createElement('span');
message.classList.add('common__media-provider_cookie-consent-message-container_message');
message.innerHTML = i18n.text('htmlSanitizer.videoCookieConsent.message');
messageWrapper.appendChild(message);
// Create the link and add it to the wrapper
const link = document.createElement('a');
link.classList.add(styles.consentLink, 'common__media-provider_cookie-consent-message-container_link');
link.href = `${PRIVACY_SETTINGS_PATTERN}?source=video`;
link.innerHTML = i18n.text('htmlSanitizer.videoCookieConsent.link');
messageWrapper.appendChild(link);
// Add the wrapper to the container
container.appendChild(messageWrapper);
return this;
}
/**
* Add a DOM container with embedded videos.
* @param {NodeList} container A DOM container.
* @returns {MediaProvider}
*/;
_proto.add = function add() {
logger.error('MediaProvider.add() needs to be implemented within an inheriting class');
return this;
}
/**
* Remove a DOM container.
* @param {NodeList} container A DOM container.
* @returns {MediaProvider}
*/;
_proto.remove = function remove(container) {
this.containers.delete(container);
return this;
}
/**
* Stops all playing videos within the DOM containers.
* @returns {MediaProvider}
*/;
_proto.stop = function stop() {
logger.error('MediaProvider.stop() needs to be implemented within an inheriting class');
return this;
};
return MediaProvider;
}();
export default MediaProvider;
/* eslint-enable class-methods-use-this */