Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.1.0]

### Changed

- Add html custom data support

## [1.0.1]

Expand Down
134 changes: 112 additions & 22 deletions src/host.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { CustomDataValues } from './shared/types';

type IAdvizeBoxedInterfaceParams = { method: string; args: unknown[] };

type IAdvizeBoxedInterface = Array<IAdvizeBoxedInterfaceParams>;
Expand Down Expand Up @@ -27,23 +29,74 @@ export function resizeIFrame(
iAdvizeSandbox: HTMLIFrameElement,
data: IframePositioning,
) {
if (data.width !== undefined && data.height !== undefined) {
const iframe = iAdvizeSandbox;
const { width, height, left, right, bottom } = data;
const shouldReset = width === 0 && height === 0;
if (shouldReset) {
iframe.style.pointerEvents = 'none';
iframe.style.width = '100vw';
iframe.style.height = '100vh';
return;
}
iframe.style.pointerEvents = 'inherit';
iframe.style.width = `${width}px`;
iframe.style.height = `${height}px`;
iframe.style.bottom = `${bottom}px`;
if (left) iframe.style.left = `${left}px`;
else iframe.style.right = `${right}px`;
const iframe = iAdvizeSandbox;
const { width, height, left, right, bottom } = data;
const shouldReset = width === 0 && height === 0;
if (shouldReset) {
iframe.style.pointerEvents = 'none';
iframe.style.width = '100vw';
iframe.style.height = '100vh';
return;
}
iframe.style.pointerEvents = 'inherit';
iframe.style.width = `${width}px`;
iframe.style.height = `${height}px`;
iframe.style.bottom = `${bottom}px`;
if (left) iframe.style.left = `${left}px`;
else iframe.style.right = `${right}px`;
}

let observers: Record<string, MutationObserver> = {};
let listeners: Record<string, () => void> = {};

function observe(
toObserve: Element,
selector: string,
callback: (values: CustomDataValues) => void,
) {
// create an observer instance
const observer = new MutationObserver((mutations) => {
mutations.forEach(({ addedNodes, removedNodes, target }) => {
// Find textContent mutation
if (
(addedNodes.length && addedNodes[0].nodeType === Node.TEXT_NODE) ||
(removedNodes.length && removedNodes[0].nodeType === Node.TEXT_NODE)
) {
callback({ [selector]: target.textContent });
}
});
});

observer.observe(toObserve, {
childList: true,
});
observers[selector] = observer;
}

function listenInput(
toListen: HTMLInputElement,
selector: string,
callback: (values: CustomDataValues) => void,
) {
let oldValue = toListen.value;

const listener = (e: Event) => {
const input = e.target as HTMLInputElement;
if (oldValue !== input.value) {
callback({ [selector]: input.value });
oldValue = input.value;
}
};
toListen.addEventListener('input', listener);

listeners[selector] = () => toListen.removeEventListener('input', listener);
}

function unObserve() {
Object.values(observers).forEach((observer) => observer.disconnect());
Object.values(listeners).forEach((removeListener) => removeListener());
observers = {};
listeners = {};
}

export function initIAdvizeHost(sandboxId: string): void {
Expand All @@ -69,6 +122,18 @@ export function initIAdvizeHost(sandboxId: string): void {
);
}

function forwardCustomDataValues(customDataValues: CustomDataValues): void {
if (!iAdvizeSandbox.contentWindow) {
return;
}
iAdvizeSandbox.contentWindow.postMessage(
{
customDataValues,
},
'*',
);
}

iAdvizeSandbox.onload = () => {
// Internal methods forwarding
const buffer = [...hostWindow.iAdvizeBoxedInterface];
Expand All @@ -93,10 +158,35 @@ export function initIAdvizeHost(sandboxId: string): void {
};

window.addEventListener('resize', forwardWindowDimensions);
window.addEventListener('message', (e) => {
if (e.source !== iAdvizeSandbox.contentWindow) {
return;
}
resizeIFrame(iAdvizeSandbox, e.data);
});
window.addEventListener(
'message',
({ source, data: { width, height, customDataSelectors } }) => {
if (source !== iAdvizeSandbox.contentWindow) {
return;
}

if (width !== undefined && height !== undefined) {
resizeIFrame(iAdvizeSandbox, { width, height });
}

if (customDataSelectors !== undefined) {
customDataSelectors?.forEach((selector: string) => {
const element = window.document.querySelector(selector);
if ((<HTMLInputElement>element)?.value !== undefined) {
listenInput(
element as HTMLInputElement,
selector,
forwardCustomDataValues,
);
} else if (element) {
observe(element, selector, forwardCustomDataValues);
}
});

if (customDataSelectors.length === 0) {
unObserve();
}
}
},
);
}
16 changes: 15 additions & 1 deletion src/iframe.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { CustomDataValues } from './shared/types';

type IAdvizeGlobal = {
[key: string]: Function;
};
Expand All @@ -8,6 +10,7 @@ type iAdvizeInterfaceParameters = {
args: unknown;
hostHeight: number;
hostWidth: number;
customDataValues: CustomDataValues;
};

type iAdvizeInterfaceParametersInternals = {
Expand Down Expand Up @@ -142,13 +145,20 @@ export function initIAdvizeIframe(
}

// Sharing the main context dimension, for sizing and positionning
const { hostWidth, hostHeight } = data;
const { hostWidth, hostHeight, customDataValues } = data;
if (hostWidth && hostHeight) {
context.host = {
width: hostWidth,
height: hostHeight,
};
}

// Send custom data values to the iAdvize tag
if (customDataValues) {
context.iAdvizeInterface.push(function (iAdvize: IAdvizeGlobal) {
iAdvize.set('app:customDataValues', customDataValues);
});
}
},
);

Expand All @@ -157,6 +167,10 @@ export function initIAdvizeIframe(
iAdvize.on('app:boundariesChange', (boundaries: unknown) => {
context.parent.postMessage(boundaries, '*');
});
// Get HTML custom data
iAdvize.on('app:customDataSelectorsChange', (selectors: string[]) => {
context.parent.postMessage({ customDataSelectors: selectors }, '*');
});
});

// Script insertion
Expand Down
1 change: 1 addition & 0 deletions src/shared/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type CustomDataValues = Record<string, string | null>;