From 4cdb652867ee990a68d918263e85df6f0a11aad8 Mon Sep 17 00:00:00 2001 From: Happy Shandilya Date: Tue, 12 Sep 2023 15:43:27 -0700 Subject: [PATCH 1/6] web parameters support removed redundant files & some clean up --- .../inAppMessageConsequenceAdapter.js | 2 + .../actions/displayIframeContent.js | 126 ++++++++++-------- .../actions/displayBanner.spec.js | 78 ----------- .../actions/displayIframeContent.spec.js | 59 +------- .../actions/displayModal.spec.js | 74 ---------- 5 files changed, 73 insertions(+), 266 deletions(-) delete mode 100644 test/unit/specs/components/Personalization/in-app-message-actions/actions/displayBanner.spec.js delete mode 100644 test/unit/specs/components/Personalization/in-app-message-actions/actions/displayModal.spec.js diff --git a/src/components/DecisioningEngine/consequenceAdapters/inAppMessageConsequenceAdapter.js b/src/components/DecisioningEngine/consequenceAdapters/inAppMessageConsequenceAdapter.js index 1249d8bc8..0bf3090b3 100644 --- a/src/components/DecisioningEngine/consequenceAdapters/inAppMessageConsequenceAdapter.js +++ b/src/components/DecisioningEngine/consequenceAdapters/inAppMessageConsequenceAdapter.js @@ -13,8 +13,10 @@ import { MESSAGE_IN_APP } from "../../Personalization/constants/schema"; import { TEXT_HTML } from "../../Personalization/constants/contentType"; export default (id, type, detail) => { + // TODO: add webParameters when available from the authoring UI in detail const { html, mobileParameters } = detail; + // TODO: Remove it once we have webParameters const webParameters = { info: "this is a placeholder" }; return { diff --git a/src/components/Personalization/in-app-message-actions/actions/displayIframeContent.js b/src/components/Personalization/in-app-message-actions/actions/displayIframeContent.js index 225f9cb00..251161101 100644 --- a/src/components/Personalization/in-app-message-actions/actions/displayIframeContent.js +++ b/src/components/Personalization/in-app-message-actions/actions/displayIframeContent.js @@ -15,18 +15,22 @@ import { parseAnchor, removeElementById } from "../utils"; import { TEXT_HTML } from "../../constants/contentType"; import { INTERACT } from "../../constants/eventType"; -const ELEMENT_TAG_CLASSNAME = "alloy-messaging-container"; -const ELEMENT_TAG_ID = "alloy-messaging-container"; - -const OVERLAY_TAG_CLASSNAME = "alloy-overlay-container"; -const OVERLAY_TAG_ID = "alloy-overlay-container"; +const ALLOY_MESSAGING_CONTAINER_ID = "alloy-messaging-container"; +const ALLOY_OVERLAY_CONTAINER_ID = "alloy-overlay-container"; const ALLOY_IFRAME_ID = "alloy-content-iframe"; const dismissMessage = () => - [ELEMENT_TAG_ID, OVERLAY_TAG_ID].forEach(removeElementById); + [ALLOY_MESSAGING_CONTAINER_ID, ALLOY_OVERLAY_CONTAINER_ID].forEach( + removeElementById + ); + +export const createElement = elementTagId => { + const element = document.createElement("div"); + element.id = elementTagId; + return element; +}; -// eslint-disable-next-line no-unused-vars -export const buildStyleFromParameters = (mobileParameters, webParameters) => { +export const buildStyleFromMobileParameters = mobileParameters => { const { verticalAlign, width, @@ -132,13 +136,6 @@ export const createIframe = (htmlContent, clickHandler) => { new Blob([htmlDocument.documentElement.outerHTML], { type: TEXT_HTML }) ); element.id = ALLOY_IFRAME_ID; - - Object.assign(element.style, { - border: "none", - width: "100%", - height: "100%" - }); - element.addEventListener("load", () => { const { addEventListener } = element.contentDocument || element.contentWindow.document; @@ -148,60 +145,75 @@ export const createIframe = (htmlContent, clickHandler) => { return element; }; -export const createContainerElement = settings => { - const { mobileParameters = {}, webParameters = {} } = settings; - const element = document.createElement("div"); - element.id = ELEMENT_TAG_ID; - element.className = `${ELEMENT_TAG_CLASSNAME}`; - Object.assign( - element.style, - buildStyleFromParameters(mobileParameters, webParameters) - ); - - return element; -}; - -export const createOverlayElement = parameter => { - const element = document.createElement("div"); - const backdropOpacity = parameter.backdropOpacity || 0.5; - const backdropColor = parameter.backdropColor || "#FFFFFF"; - element.id = OVERLAY_TAG_ID; - element.className = `${OVERLAY_TAG_CLASSNAME}`; - - Object.assign(element.style, { - position: "fixed", - top: "0", - left: "0", - width: "100%", - height: "100%", - background: "transparent", - opacity: backdropOpacity, - backgroundColor: backdropColor - }); - - return element; -}; - export const displayHTMLContentInIframe = (settings, interact) => { dismissMessage(); - const { content, contentType, mobileParameters } = settings; + const { content, contentType, mobileParameters, webParameters } = settings; if (contentType !== TEXT_HTML) { return; } - const container = createContainerElement(settings); + const container = createElement(ALLOY_MESSAGING_CONTAINER_ID); const iframe = createIframe(content, createIframeClickHandler(interact)); - container.appendChild(iframe); + const overlay = createElement(ALLOY_OVERLAY_CONTAINER_ID); - if (mobileParameters.uiTakeover) { - const overlay = createOverlayElement(mobileParameters); - document.body.appendChild(overlay); - document.body.style.overflow = "hidden"; + container.appendChild(iframe); + if (webParameters && webParameters.info !== "this is a placeholder") { + Object.assign(iframe.style, webParameters[ALLOY_IFRAME_ID].style); + Object.assign( + container.style, + webParameters[ALLOY_MESSAGING_CONTAINER_ID].style + ); + if (webParameters[ALLOY_OVERLAY_CONTAINER_ID].params.enabled) { + Object.assign( + overlay.style, + webParameters[ALLOY_OVERLAY_CONTAINER_ID].style + ); + document.body.appendChild(overlay); + document.body.style.overflow = "hidden"; + } + const parentElementSelector = + webParameters[ALLOY_MESSAGING_CONTAINER_ID].params.parentElement; + if (parentElementSelector) { + const parentElement = document.querySelector(parentElementSelector); + if (parentElement) { + parentElement[ + webParameters[ALLOY_MESSAGING_CONTAINER_ID].params.insertionMethod + ](container); + } else { + document.body.appendChild(container); + } + } + } else { + Object.assign(iframe.style, { + border: "none", + width: "100%", + height: "100%" + }); + Object.assign( + container.style, + buildStyleFromMobileParameters(mobileParameters) + ); + if (mobileParameters.uiTakeover) { + const backdropOpacity = mobileParameters.backdropOpacity || 0.5; + const backdropColor = mobileParameters.backdropColor || "#FFFFFF"; + Object.assign(overlay.style, { + position: "fixed", + top: "0", + left: "0", + width: "100%", + height: "100%", + background: "transparent", + opacity: backdropOpacity, + backgroundColor: backdropColor + }); + document.body.appendChild(overlay); + document.body.style.overflow = "hidden"; + } + document.body.appendChild(container); } - document.body.appendChild(container); }; export default (settings, collect) => { diff --git a/test/unit/specs/components/Personalization/in-app-message-actions/actions/displayBanner.spec.js b/test/unit/specs/components/Personalization/in-app-message-actions/actions/displayBanner.spec.js deleted file mode 100644 index 9b85d9f29..000000000 --- a/test/unit/specs/components/Personalization/in-app-message-actions/actions/displayBanner.spec.js +++ /dev/null @@ -1,78 +0,0 @@ -/* -Copyright 2023 Adobe. All rights reserved. -This file is licensed to you under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. You may obtain a copy -of the License at http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software distributed under -the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS -OF ANY KIND, either express or implied. See the License for the specific language -governing permissions and limitations under the License. -*/ -import { createNode } from "../../../../../../../src/utils/dom"; -import { DIV } from "../../../../../../../src/constants/tagName"; -import displayIframeContent from "../../../../../../../src/components/Personalization/in-app-message-actions/actions/displayIframeContent"; -import { TEXT_HTML } from "../../../../../../../src/components/Personalization/constants/contentType"; - -describe("Personalization::IAM:banner", () => { - it("inserts banner into dom", async () => { - const something = createNode( - DIV, - { className: "something" }, - { - innerHTML: - "

Amet cillum consectetur elit cupidatat voluptate nisi duis et occaecat enim pariatur.

" - } - ); - - document.body.append(something); - - await displayIframeContent({ - mobileParameters: { - verticalAlign: "center", - dismissAnimation: "top", - verticalInset: 0, - backdropOpacity: 0.2, - cornerRadius: 15, - horizontalInset: 0, - uiTakeover: false, - horizontalAlign: "center", - width: 80, - displayAnimation: "top", - backdropColor: "#000000", - height: 60 - }, - content: `
banner
Alf Says`, - contentType: TEXT_HTML - }); - - const overlayContainer = document.querySelector( - "div#alloy-overlay-container" - ); - const messagingContainer = document.querySelector( - "div#alloy-messaging-container" - ); - - expect(overlayContainer).toBeNull(); - expect(messagingContainer).not.toBeNull(); - - expect(messagingContainer.parentNode).toEqual(document.body); - expect(messagingContainer.nextElementSibling).toBeNull(); - - const iframe = document.querySelector( - ".alloy-messaging-container > iframe" - ); - - expect(iframe).not.toBeNull(); - - await new Promise(resolve => { - iframe.addEventListener("load", () => { - resolve(); - }); - }); - - expect( - (iframe.contentDocument || iframe.contentWindow.document).body.outerHTML - ).toContain("Alf Says"); - }); -}); diff --git a/test/unit/specs/components/Personalization/in-app-message-actions/actions/displayIframeContent.spec.js b/test/unit/specs/components/Personalization/in-app-message-actions/actions/displayIframeContent.spec.js index af01778e8..fb1a005f1 100644 --- a/test/unit/specs/components/Personalization/in-app-message-actions/actions/displayIframeContent.spec.js +++ b/test/unit/specs/components/Personalization/in-app-message-actions/actions/displayIframeContent.spec.js @@ -10,8 +10,7 @@ OF ANY KIND, either express or implied. See the License for the specific languag governing permissions and limitations under the License. */ import { - buildStyleFromParameters, - createOverlayElement, + buildStyleFromMobileParameters, createIframe, createIframeClickHandler, displayHTMLContentInIframe @@ -46,11 +45,7 @@ describe("DOM Actions on Iframe", () => { verticalInset: 10, uiTakeover: true }; - - const webParameters = {}; - - const style = buildStyleFromParameters(mobileParameters, webParameters); - + const style = buildStyleFromMobileParameters(mobileParameters); expect(style.width).toBe("80%"); expect(style.backgroundColor).toBe("rgba(0, 0, 0, 0.7)"); expect(style.borderRadius).toBe("10px"); @@ -62,26 +57,6 @@ describe("DOM Actions on Iframe", () => { }); }); - describe("createOverlayElement", () => { - it("should create overlay element with correct styles", () => { - const parameter = { - backdropOpacity: 0.8, - backdropColor: "#000000" - }; - - const overlayElement = createOverlayElement(parameter); - - expect(overlayElement.id).toBe("alloy-overlay-container"); - expect(overlayElement.style.position).toBe("fixed"); - expect(overlayElement.style.top).toBe("0px"); - expect(overlayElement.style.left).toBe("0px"); - expect(overlayElement.style.width).toBe("100%"); - expect(overlayElement.style.height).toBe("100%"); - expect(overlayElement.style.background).toBe("rgb(0, 0, 0)"); - expect(overlayElement.style.opacity).toBe("0.8"); - expect(overlayElement.style.backgroundColor).toBe("rgb(0, 0, 0)"); - }); - }); describe("createIframe function", () => { it("should create an iframe element with specified properties", () => { const mockHtmlContent = @@ -89,13 +64,9 @@ describe("DOM Actions on Iframe", () => { const mockClickHandler = jasmine.createSpy("clickHandler"); const iframe = createIframe(mockHtmlContent, mockClickHandler); - expect(iframe).toBeDefined(); expect(iframe instanceof HTMLIFrameElement).toBe(true); expect(iframe.src).toContain("blob:"); - expect(iframe.style.border).toBe("none"); - expect(iframe.style.width).toBe("100%"); - expect(iframe.style.height).toBe("100%"); }); it("should set 'nonce' attribute on script tag if it exists", async () => { @@ -285,9 +256,7 @@ describe("DOM Actions on Iframe", () => { let originalAppendChild; let originalBodyStyle; let mockCollect; - let originalCreateContainerElement; let originalCreateIframe; - let originalCreateOverlayElement; beforeEach(() => { mockCollect = jasmine.createSpy("collect"); @@ -295,16 +264,6 @@ describe("DOM Actions on Iframe", () => { document.body.appendChild = jasmine.createSpy("appendChild"); originalBodyStyle = document.body.style; document.body.style = {}; - - originalCreateContainerElement = window.createContainerElement; - window.createContainerElement = jasmine - .createSpy("createContainerElement") - .and.callFake(() => { - const element = document.createElement("div"); - element.id = "alloy-messaging-container"; - return element; - }); - originalCreateIframe = window.createIframe; window.createIframe = jasmine .createSpy("createIframe") @@ -313,23 +272,12 @@ describe("DOM Actions on Iframe", () => { element.id = "alloy-content-iframe"; return element; }); - - originalCreateOverlayElement = window.createOverlayElement; - window.createOverlayElement = jasmine - .createSpy("createOverlayElement") - .and.callFake(() => { - const element = document.createElement("div"); - element.id = "alloy-overlay-container"; - return element; - }); }); afterEach(() => { document.body.appendChild = originalAppendChild; document.body.style = originalBodyStyle; document.body.innerHTML = ""; - window.createContainerElement = originalCreateContainerElement; - window.createOverlayElement = originalCreateOverlayElement; window.createIframe = originalCreateIframe; }); @@ -351,9 +299,6 @@ describe("DOM Actions on Iframe", () => { backdropColor: "#4CA206", height: 63 }, - webParameters: { - info: "this is a placeholder" - }, content: '\n\n\n Bumper Sale!\n \n\n\n
\n \n

Black Friday Sale!

\n Technology Image\n

Don\'t miss out on our incredible discounts and deals at our gadgets!

\n
\n Shop\n Dismiss\n
\n
\n\n\n\n', contentType: TEXT_HTML, diff --git a/test/unit/specs/components/Personalization/in-app-message-actions/actions/displayModal.spec.js b/test/unit/specs/components/Personalization/in-app-message-actions/actions/displayModal.spec.js deleted file mode 100644 index 1edb52313..000000000 --- a/test/unit/specs/components/Personalization/in-app-message-actions/actions/displayModal.spec.js +++ /dev/null @@ -1,74 +0,0 @@ -/* -Copyright 2023 Adobe. All rights reserved. -This file is licensed to you under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. You may obtain a copy -of the License at http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software distributed under -the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS -OF ANY KIND, either express or implied. See the License for the specific language -governing permissions and limitations under the License. -*/ -import { createNode } from "../../../../../../../src/utils/dom"; -import { DIV } from "../../../../../../../src/constants/tagName"; -import displayIframeContent from "../../../../../../../src/components/Personalization/in-app-message-actions/actions/displayIframeContent"; -import { TEXT_HTML } from "../../../../../../../src/components/Personalization/constants/contentType"; - -describe("Personalization::IAM:modal", () => { - it("inserts modal into dom", async () => { - const something = createNode( - DIV, - { className: "something" }, - { - innerHTML: - "

Amet cillum consectetur elit cupidatat voluptate nisi duis et occaecat enim pariatur.

" - } - ); - - document.body.append(something); - - await displayIframeContent({ - mobileParameters: { - verticalAlign: "center", - dismissAnimation: "top", - verticalInset: 0, - backdropOpacity: 0.2, - cornerRadius: 15, - horizontalInset: 0, - uiTakeover: true, - horizontalAlign: "center", - width: 80, - displayAnimation: "top", - backdropColor: "#000000", - height: 60 - }, - content: `
modal
Alf Says`, - contentType: TEXT_HTML - }); - document.querySelector("div#alloy-overlay-container"); - const messagingContainer = document.querySelector( - "div#alloy-messaging-container" - ); - - expect(messagingContainer).not.toBeNull(); - - expect(messagingContainer.parentNode).toEqual(document.body); - expect(messagingContainer.nextElementSibling).toBeNull(); - - const iframe = document.querySelector( - ".alloy-messaging-container > iframe" - ); - - expect(iframe).not.toBeNull(); - - await new Promise(resolve => { - iframe.addEventListener("load", () => { - resolve(); - }); - }); - - expect( - (iframe.contentDocument || iframe.contentWindow.document).body.outerHTML - ).toContain("Alf Says"); - }); -}); From 3d255a6e66c6afc65a888ef0b1ffea73498d17b8 Mon Sep 17 00:00:00 2001 From: Happy Shandilya Date: Wed, 13 Sep 2023 11:51:44 -0700 Subject: [PATCH 2/6] code refactoring --- .../actions/displayIframeContent.js | 234 +++++++++--------- .../in-app-message-actions/utils.js | 5 + 2 files changed, 128 insertions(+), 111 deletions(-) diff --git a/src/components/Personalization/in-app-message-actions/actions/displayIframeContent.js b/src/components/Personalization/in-app-message-actions/actions/displayIframeContent.js index 251161101..b867c4e33 100644 --- a/src/components/Personalization/in-app-message-actions/actions/displayIframeContent.js +++ b/src/components/Personalization/in-app-message-actions/actions/displayIframeContent.js @@ -11,9 +11,10 @@ governing permissions and limitations under the License. */ import { getNonce } from "../../dom-actions/dom"; -import { parseAnchor, removeElementById } from "../utils"; +import { createElement, parseAnchor, removeElementById } from "../utils"; import { TEXT_HTML } from "../../constants/contentType"; import { INTERACT } from "../../constants/eventType"; +import { assign } from "../../../../utils"; const ALLOY_MESSAGING_CONTAINER_ID = "alloy-messaging-container"; const ALLOY_OVERLAY_CONTAINER_ID = "alloy-overlay-container"; @@ -24,65 +25,6 @@ const dismissMessage = () => removeElementById ); -export const createElement = elementTagId => { - const element = document.createElement("div"); - element.id = elementTagId; - return element; -}; - -export const buildStyleFromMobileParameters = mobileParameters => { - const { - verticalAlign, - width, - horizontalAlign, - backdropColor, - height, - cornerRadius, - horizontalInset, - verticalInset, - uiTakeover = false - } = mobileParameters; - - const style = { - width: width ? `${width}%` : "100%", - backgroundColor: backdropColor || "rgba(0, 0, 0, 0.5)", - borderRadius: cornerRadius ? `${cornerRadius}px` : "0px", - border: "none", - position: uiTakeover ? "fixed" : "relative", - overflow: "hidden" - }; - if (horizontalAlign === "left") { - style.left = horizontalInset ? `${horizontalInset}%` : "0"; - } else if (horizontalAlign === "right") { - style.right = horizontalInset ? `${horizontalInset}%` : "0"; - } else if (horizontalAlign === "center") { - style.left = "50%"; - style.transform = "translateX(-50%)"; - } - - if (verticalAlign === "top") { - style.top = verticalInset ? `${verticalInset}%` : "0"; - } else if (verticalAlign === "bottom") { - style.position = "fixed"; - style.bottom = verticalInset ? `${verticalInset}%` : "0"; - } else if (verticalAlign === "center") { - style.top = "50%"; - style.transform = `${ - horizontalAlign === "center" ? `${style.transform} ` : "" - }translateY(-50%)`; - style.display = "flex"; - style.alignItems = "center"; - style.justifyContent = "center"; - } - - if (height) { - style.height = `${height}vh`; - } else { - style.height = "100%"; - } - return style; -}; - const setWindowLocationHref = link => { window.location.assign(link); }; @@ -145,6 +87,125 @@ export const createIframe = (htmlContent, clickHandler) => { return element; }; +const displayBasedOnWebParams = (iframe, webParameters, container, overlay) => { + const { style: iframeStyle = {} } = webParameters[ALLOY_IFRAME_ID]; + const { + style: messagingStyle = {}, + params: messagingParams = {} + } = webParameters[ALLOY_MESSAGING_CONTAINER_ID]; + + const { + style: overlayStyle = {}, + params: overlayParams = {} + } = webParameters[ALLOY_OVERLAY_CONTAINER_ID]; + + assign(iframe.style, iframeStyle); + assign(container.style, messagingStyle); + + if (overlayParams.enabled) { + assign(overlay.style, overlayStyle); + document.body.appendChild(overlay); + document.body.style.overflow = "hidden"; + } + + const { + paramElement = "body", + insertionMethod = "appendChild" + } = messagingParams; + + const element = document.querySelector(paramElement); + element[insertionMethod](container); +}; + +export const buildStyleFromMobileParameters = mobileParameters => { + const { + verticalAlign, + width, + horizontalAlign, + backdropColor, + height, + cornerRadius, + horizontalInset, + verticalInset, + uiTakeover = false + } = mobileParameters; + + const style = { + width: width ? `${width}%` : "100%", + backgroundColor: backdropColor || "rgba(0, 0, 0, 0.5)", + borderRadius: cornerRadius ? `${cornerRadius}px` : "0px", + border: "none", + position: uiTakeover ? "fixed" : "relative", + overflow: "hidden" + }; + if (horizontalAlign === "left") { + style.left = horizontalInset ? `${horizontalInset}%` : "0"; + } else if (horizontalAlign === "right") { + style.right = horizontalInset ? `${horizontalInset}%` : "0"; + } else if (horizontalAlign === "center") { + style.left = "50%"; + style.transform = "translateX(-50%)"; + } + + if (verticalAlign === "top") { + style.top = verticalInset ? `${verticalInset}%` : "0"; + } else if (verticalAlign === "bottom") { + style.position = "fixed"; + style.bottom = verticalInset ? `${verticalInset}%` : "0"; + } else if (verticalAlign === "center") { + style.top = "50%"; + style.transform = `${ + horizontalAlign === "center" ? `${style.transform} ` : "" + }translateY(-50%)`; + style.display = "flex"; + style.alignItems = "center"; + style.justifyContent = "center"; + } + + if (height) { + style.height = `${height}vh`; + } else { + style.height = "100%"; + } + return style; +}; + +export const mobileOverlay = (overlay, mobileParameters) => { + const { backdropOpacity, backdropColor } = mobileParameters; + const opacity = backdropOpacity || 0.5; + const color = backdropColor || "#FFFFFF"; + assign(overlay.style, { + position: "fixed", + top: "0", + left: "0", + width: "100%", + height: "100%", + background: "transparent", + opacity, + backgroundColor: color + }); + document.body.appendChild(overlay); + document.body.style.overflow = "hidden"; +}; + +const displayBasedOnMobileParams = ( + iframe, + container, + mobileParameters, + overlay +) => { + assign(iframe.style, { + border: "none", + width: "100%", + height: "100%" + }); + assign(container.style, buildStyleFromMobileParameters(mobileParameters)); + if (mobileParameters.uiTakeover) { + mobileOverlay(overlay, mobileParameters); + } + document.body.appendChild(container); +}; + export const displayHTMLContentInIframe = (settings, interact) => { dismissMessage(); const { content, contentType, mobileParameters, webParameters } = settings; @@ -161,58 +222,9 @@ export const displayHTMLContentInIframe = (settings, interact) => { container.appendChild(iframe); if (webParameters && webParameters.info !== "this is a placeholder") { - Object.assign(iframe.style, webParameters[ALLOY_IFRAME_ID].style); - Object.assign( - container.style, - webParameters[ALLOY_MESSAGING_CONTAINER_ID].style - ); - if (webParameters[ALLOY_OVERLAY_CONTAINER_ID].params.enabled) { - Object.assign( - overlay.style, - webParameters[ALLOY_OVERLAY_CONTAINER_ID].style - ); - document.body.appendChild(overlay); - document.body.style.overflow = "hidden"; - } - const parentElementSelector = - webParameters[ALLOY_MESSAGING_CONTAINER_ID].params.parentElement; - if (parentElementSelector) { - const parentElement = document.querySelector(parentElementSelector); - if (parentElement) { - parentElement[ - webParameters[ALLOY_MESSAGING_CONTAINER_ID].params.insertionMethod - ](container); - } else { - document.body.appendChild(container); - } - } + displayBasedOnWebParams(iframe, webParameters, container, overlay); } else { - Object.assign(iframe.style, { - border: "none", - width: "100%", - height: "100%" - }); - Object.assign( - container.style, - buildStyleFromMobileParameters(mobileParameters) - ); - if (mobileParameters.uiTakeover) { - const backdropOpacity = mobileParameters.backdropOpacity || 0.5; - const backdropColor = mobileParameters.backdropColor || "#FFFFFF"; - Object.assign(overlay.style, { - position: "fixed", - top: "0", - left: "0", - width: "100%", - height: "100%", - background: "transparent", - opacity: backdropOpacity, - backgroundColor: backdropColor - }); - document.body.appendChild(overlay); - document.body.style.overflow = "hidden"; - } - document.body.appendChild(container); + displayBasedOnMobileParams(iframe, container, mobileParameters, overlay); } }; diff --git a/src/components/Personalization/in-app-message-actions/utils.js b/src/components/Personalization/in-app-message-actions/utils.js index b8f82bc49..aa4f42567 100644 --- a/src/components/Personalization/in-app-message-actions/utils.js +++ b/src/components/Personalization/in-app-message-actions/utils.js @@ -74,3 +74,8 @@ export const parseAnchor = anchor => { uuid }; }; +export const createElement = elementTagId => { + const element = document.createElement("div"); + element.id = elementTagId; + return element; +}; From 4faecbc14a32cc4733f08bf2c9bfbc5364d39794 Mon Sep 17 00:00:00 2001 From: Happy Shandilya Date: Wed, 13 Sep 2023 14:36:00 -0700 Subject: [PATCH 3/6] adding test for web parameteres --- .../actions/displayIframeContent.spec.js | 117 +++++++++++++++++- 1 file changed, 116 insertions(+), 1 deletion(-) diff --git a/test/unit/specs/components/Personalization/in-app-message-actions/actions/displayIframeContent.spec.js b/test/unit/specs/components/Personalization/in-app-message-actions/actions/displayIframeContent.spec.js index fb1a005f1..708b799ab 100644 --- a/test/unit/specs/components/Personalization/in-app-message-actions/actions/displayIframeContent.spec.js +++ b/test/unit/specs/components/Personalization/in-app-message-actions/actions/displayIframeContent.spec.js @@ -265,6 +265,7 @@ describe("DOM Actions on Iframe", () => { originalBodyStyle = document.body.style; document.body.style = {}; originalCreateIframe = window.createIframe; + window.createIframe = jasmine .createSpy("createIframe") .and.callFake(() => { @@ -281,7 +282,7 @@ describe("DOM Actions on Iframe", () => { window.createIframe = originalCreateIframe; }); - it("should display HTML content in iframe with overlay", () => { + it("should display HTML content in iframe with overlay using mobile parameters", () => { const settings = { type: "custom", mobileParameters: { @@ -326,5 +327,119 @@ describe("DOM Actions on Iframe", () => { expect(document.body.appendChild).toHaveBeenCalledTimes(2); expect(document.body.style.overflow).toBe("hidden"); }); + + it("should display HTML content in iframe with overlay using web parameters", () => { + const settings = { + type: "custom", + webParameters: { + "alloy-overlay-container": { + style: { + position: "fixed", + top: "0", + left: "0", + width: "100%", + height: "100%", + background: "transparent", + opacity: 0.5, + backgroundColor: "#FFFFFF" + }, + params: { + enabled: true + } + }, + "alloy-messaging-container": { + style: { + width: "72%", + backgroundColor: "orange", + borderRadius: "20px", + border: "none", + position: "fixed", + overflow: "hidden", + left: "50%", + transform: "translateX(-50%) translateY(-50%)", + top: "50%", + display: "flex", + alignItems: "center", + justifyContent: "center", + height: "63vh" + }, + params: { + parentElement: "body", + insertionMethod: "appendChild" + } + }, + "alloy-content-iframe": { + style: { + width: "100%", + height: "100%" + } + } + }, + content: + '\n\n\n Bumper Sale!\n \n\n\n
\n \n

Black Friday Sale!

\n Technology Image\n

Don\'t miss out on our incredible discounts and deals at our gadgets!

\n
\n Shop\n Dismiss\n
\n
\n\n\n\n', + contentType: TEXT_HTML, + schema: "https://ns.adobe.com/personalization/message/in-app" + }; + + displayHTMLContentInIframe(settings, mockCollect); + expect(document.body.appendChild).toHaveBeenCalledTimes(2); + expect(document.body.style.overflow).toBe("hidden"); + }); + it("should display HTML content in iframe with no overlay using web parameters", () => { + const settings = { + type: "custom", + webParameters: { + "alloy-overlay-container": { + style: { + position: "fixed", + top: "0", + left: "0", + width: "100%", + height: "100%", + background: "transparent", + opacity: 0.5, + backgroundColor: "#FFFFFF" + }, + params: { + enabled: false + } + }, + "alloy-messaging-container": { + style: { + width: "72%", + backgroundColor: "orange", + borderRadius: "20px", + border: "none", + position: "fixed", + overflow: "hidden", + left: "50%", + transform: "translateX(-50%) translateY(-50%)", + top: "50%", + display: "flex", + alignItems: "center", + justifyContent: "center", + height: "63vh" + }, + params: { + parentElement: "body", + insertionMethod: "appendChild" + } + }, + "alloy-content-iframe": { + style: { + width: "100%", + height: "100%" + } + } + }, + content: + '\n\n\n Bumper Sale!\n \n\n\n
\n \n

Black Friday Sale!

\n Technology Image\n

Don\'t miss out on our incredible discounts and deals at our gadgets!

\n
\n Shop\n Dismiss\n
\n
\n\n\n\n', + contentType: TEXT_HTML, + schema: "https://ns.adobe.com/personalization/message/in-app" + }; + + displayHTMLContentInIframe(settings, mockCollect); + expect(document.body.appendChild).toHaveBeenCalledTimes(1); + }); }); }); From b6147d7445139a18db5a27e8b803d3480639e602 Mon Sep 17 00:00:00 2001 From: Happy Shandilya Date: Thu, 21 Sep 2023 14:36:10 -0700 Subject: [PATCH 4/6] code refactoring based on review --- .../actions/displayIframeContent.js | 51 +++++++++---------- .../actions/displayIframeContent.spec.js | 1 + 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/src/components/Personalization/in-app-message-actions/actions/displayIframeContent.js b/src/components/Personalization/in-app-message-actions/actions/displayIframeContent.js index b867c4e33..d15701050 100644 --- a/src/components/Personalization/in-app-message-actions/actions/displayIframeContent.js +++ b/src/components/Personalization/in-app-message-actions/actions/displayIframeContent.js @@ -87,7 +87,7 @@ export const createIframe = (htmlContent, clickHandler) => { return element; }; -const displayBasedOnWebParams = (iframe, webParameters, container, overlay) => { +const renderElement = (iframe, webParameters, container, overlay) => { const { style: iframeStyle = {} } = webParameters[ALLOY_IFRAME_ID]; const { style: messagingStyle = {}, @@ -102,7 +102,8 @@ const displayBasedOnWebParams = (iframe, webParameters, container, overlay) => { assign(iframe.style, iframeStyle); assign(container.style, messagingStyle); - if (overlayParams.enabled) { + const { enabled = true } = overlayParams; + if (enabled) { assign(overlay.style, overlayStyle); document.body.appendChild(overlay); document.body.style.overflow = "hidden"; @@ -170,11 +171,11 @@ export const buildStyleFromMobileParameters = mobileParameters => { return style; }; -export const mobileOverlay = (overlay, mobileParameters) => { +export const mobileOverlay = mobileParameters => { const { backdropOpacity, backdropColor } = mobileParameters; const opacity = backdropOpacity || 0.5; const color = backdropColor || "#FFFFFF"; - assign(overlay.style, { + const style = { position: "fixed", top: "0", left: "0", @@ -183,27 +184,8 @@ export const mobileOverlay = (overlay, mobileParameters) => { background: "transparent", opacity, backgroundColor: color - }); - document.body.appendChild(overlay); - document.body.style.overflow = "hidden"; -}; - -const displayBasedOnMobileParams = ( - iframe, - container, - mobileParameters, - overlay -) => { - assign(iframe.style, { - border: "none", - width: "100%", - height: "100%" - }); - assign(container.style, buildStyleFromMobileParameters(mobileParameters)); - if (mobileParameters.uiTakeover) { - mobileOverlay(overlay, mobileParameters); - } - document.body.appendChild(container); + }; + return style; }; export const displayHTMLContentInIframe = (settings, interact) => { @@ -222,9 +204,24 @@ export const displayHTMLContentInIframe = (settings, interact) => { container.appendChild(iframe); if (webParameters && webParameters.info !== "this is a placeholder") { - displayBasedOnWebParams(iframe, webParameters, container, overlay); + renderElement(iframe, webParameters, container, overlay); } else { - displayBasedOnMobileParams(iframe, container, mobileParameters, overlay); + assign(webParameters, { + "alloy-content-iframe": { + style: { + border: "none", + width: "100%", + height: "100%" + } + }, + "alloy-messaging-container": { + style: buildStyleFromMobileParameters(mobileParameters) + }, + "alloy-overlay-container": { + style: mobileOverlay(mobileParameters) + } + }); + renderElement(iframe, webParameters, container, overlay); } }; diff --git a/test/unit/specs/components/Personalization/in-app-message-actions/actions/displayIframeContent.spec.js b/test/unit/specs/components/Personalization/in-app-message-actions/actions/displayIframeContent.spec.js index 708b799ab..dc94f48c9 100644 --- a/test/unit/specs/components/Personalization/in-app-message-actions/actions/displayIframeContent.spec.js +++ b/test/unit/specs/components/Personalization/in-app-message-actions/actions/displayIframeContent.spec.js @@ -285,6 +285,7 @@ describe("DOM Actions on Iframe", () => { it("should display HTML content in iframe with overlay using mobile parameters", () => { const settings = { type: "custom", + webParameters: { info: "this is a placeholder" }, mobileParameters: { verticalAlign: "center", dismissAnimation: "bottom", From 2fb8f03e8badfc8836f0f1136c4042c3e179120f Mon Sep 17 00:00:00 2001 From: Jason Waters Date: Fri, 22 Sep 2023 10:45:18 -0600 Subject: [PATCH 5/6] webProperties (#1039) * webProperties * webProperties --- .../actions/displayIframeContent.js | 140 +++++++++++------- .../actions/displayIframeContent.spec.js | 13 +- 2 files changed, 98 insertions(+), 55 deletions(-) diff --git a/src/components/Personalization/in-app-message-actions/actions/displayIframeContent.js b/src/components/Personalization/in-app-message-actions/actions/displayIframeContent.js index d15701050..f06693d49 100644 --- a/src/components/Personalization/in-app-message-actions/actions/displayIframeContent.js +++ b/src/components/Personalization/in-app-message-actions/actions/displayIframeContent.js @@ -87,35 +87,27 @@ export const createIframe = (htmlContent, clickHandler) => { return element; }; -const renderElement = (iframe, webParameters, container, overlay) => { - const { style: iframeStyle = {} } = webParameters[ALLOY_IFRAME_ID]; - const { - style: messagingStyle = {}, - params: messagingParams = {} - } = webParameters[ALLOY_MESSAGING_CONTAINER_ID]; - - const { - style: overlayStyle = {}, - params: overlayParams = {} - } = webParameters[ALLOY_OVERLAY_CONTAINER_ID]; - - assign(iframe.style, iframeStyle); - assign(container.style, messagingStyle); - - const { enabled = true } = overlayParams; - if (enabled) { - assign(overlay.style, overlayStyle); - document.body.appendChild(overlay); - document.body.style.overflow = "hidden"; - } - - const { - paramElement = "body", - insertionMethod = "appendChild" - } = messagingParams; - - const element = document.querySelector(paramElement); - element[insertionMethod](container); +const renderMessage = (iframe, webParameters, container, overlay) => { + [ + { id: ALLOY_OVERLAY_CONTAINER_ID, element: overlay }, + { id: ALLOY_MESSAGING_CONTAINER_ID, element: container }, + { id: ALLOY_IFRAME_ID, element: iframe } + ].forEach(({ id, element }) => { + const { style = {}, params = {} } = webParameters[id]; + + assign(element.style, style); + + const { + parentElement = "body", + insertionMethod = "appendChild", + enabled = true + } = params; + + const parent = document.querySelector(parentElement); + if (enabled && parent && typeof parent[insertionMethod] === "function") { + parent[insertionMethod](element); + } + }); }; export const buildStyleFromMobileParameters = mobileParameters => { @@ -188,41 +180,85 @@ export const mobileOverlay = mobileParameters => { return style; }; +const isValidWebParameters = webParameters => { + if (!webParameters) { + return false; + } + + const ids = Object.keys(webParameters); + + if (!ids.includes(ALLOY_MESSAGING_CONTAINER_ID)) { + return false; + } + + if (!ids.includes(ALLOY_OVERLAY_CONTAINER_ID)) { + return false; + } + + const values = Object.values(webParameters); + + for (let i = 0; i < values.length; i += 1) { + if (!Object.prototype.hasOwnProperty.call(values[i], "style")) { + return false; + } + } + + return true; +}; + +const generateWebParameters = mobileParameters => { + const { uiTakeover = false } = mobileParameters; + + return { + [ALLOY_IFRAME_ID]: { + style: { + border: "none", + width: "100%", + height: "100%" + }, + params: { + enabled: true, + parentElement: "#alloy-messaging-container", + insertionMethod: "appendChild" + } + }, + [ALLOY_MESSAGING_CONTAINER_ID]: { + style: buildStyleFromMobileParameters(mobileParameters), + params: { + enabled: true, + parentElement: "body", + insertionMethod: "appendChild" + } + }, + [ALLOY_OVERLAY_CONTAINER_ID]: { + style: mobileOverlay(mobileParameters), + params: { + enabled: uiTakeover === true, + parentElement: "body", + insertionMethod: "appendChild" + } + } + }; +}; + export const displayHTMLContentInIframe = (settings, interact) => { dismissMessage(); - const { content, contentType, mobileParameters, webParameters } = settings; + const { content, contentType, mobileParameters } = settings; + let { webParameters } = settings; if (contentType !== TEXT_HTML) { return; } const container = createElement(ALLOY_MESSAGING_CONTAINER_ID); - const iframe = createIframe(content, createIframeClickHandler(interact)); - const overlay = createElement(ALLOY_OVERLAY_CONTAINER_ID); - container.appendChild(iframe); - if (webParameters && webParameters.info !== "this is a placeholder") { - renderElement(iframe, webParameters, container, overlay); - } else { - assign(webParameters, { - "alloy-content-iframe": { - style: { - border: "none", - width: "100%", - height: "100%" - } - }, - "alloy-messaging-container": { - style: buildStyleFromMobileParameters(mobileParameters) - }, - "alloy-overlay-container": { - style: mobileOverlay(mobileParameters) - } - }); - renderElement(iframe, webParameters, container, overlay); + if (!isValidWebParameters(webParameters)) { + webParameters = generateWebParameters(mobileParameters); } + + renderMessage(iframe, webParameters, container, overlay); }; export default (settings, collect) => { diff --git a/test/unit/specs/components/Personalization/in-app-message-actions/actions/displayIframeContent.spec.js b/test/unit/specs/components/Personalization/in-app-message-actions/actions/displayIframeContent.spec.js index dc94f48c9..92e4fa42c 100644 --- a/test/unit/specs/components/Personalization/in-app-message-actions/actions/displayIframeContent.spec.js +++ b/test/unit/specs/components/Personalization/in-app-message-actions/actions/displayIframeContent.spec.js @@ -326,7 +326,6 @@ describe("DOM Actions on Iframe", () => { displayHTMLContentInIframe(settings, mockCollect); expect(document.body.appendChild).toHaveBeenCalledTimes(2); - expect(document.body.style.overflow).toBe("hidden"); }); it("should display HTML content in iframe with overlay using web parameters", () => { @@ -373,6 +372,11 @@ describe("DOM Actions on Iframe", () => { style: { width: "100%", height: "100%" + }, + params: { + enabled: true, + parentElement: "#alloy-messaging-container", + insertionMethod: "appendChild" } } }, @@ -384,11 +388,9 @@ describe("DOM Actions on Iframe", () => { displayHTMLContentInIframe(settings, mockCollect); expect(document.body.appendChild).toHaveBeenCalledTimes(2); - expect(document.body.style.overflow).toBe("hidden"); }); it("should display HTML content in iframe with no overlay using web parameters", () => { const settings = { - type: "custom", webParameters: { "alloy-overlay-container": { style: { @@ -430,6 +432,11 @@ describe("DOM Actions on Iframe", () => { style: { width: "100%", height: "100%" + }, + params: { + enabled: true, + parentElement: "#alloy-messaging-container", + insertionMethod: "appendChild" } } }, From 9b2ee204ede2e33a31895d0f95a7ffaba3d13ed9 Mon Sep 17 00:00:00 2001 From: Jason Waters Date: Fri, 22 Sep 2023 12:00:47 -0600 Subject: [PATCH 6/6] improve isValidWebParameters --- .../actions/displayIframeContent.js | 26 ++++++++++++++++++- .../actions/displayIframeContent.spec.js | 11 +++++--- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/components/Personalization/in-app-message-actions/actions/displayIframeContent.js b/src/components/Personalization/in-app-message-actions/actions/displayIframeContent.js index beb46f47b..4582c1df6 100644 --- a/src/components/Personalization/in-app-message-actions/actions/displayIframeContent.js +++ b/src/components/Personalization/in-app-message-actions/actions/displayIframeContent.js @@ -16,7 +16,6 @@ import { TEXT_HTML } from "../../constants/contentType"; import { assign } from "../../../../utils"; import { getEventType } from "../../constants/propositionEventType"; - const ALLOY_MESSAGING_CONTAINER_ID = "alloy-messaging-container"; const ALLOY_OVERLAY_CONTAINER_ID = "alloy-overlay-container"; const ALLOY_IFRAME_ID = "alloy-content-iframe"; @@ -181,6 +180,8 @@ export const mobileOverlay = mobileParameters => { return style; }; +const REQUIRED_PARAMS = ["enabled", "parentElement", "insertionMethod"]; + const isValidWebParameters = webParameters => { if (!webParameters) { return false; @@ -202,12 +203,31 @@ const isValidWebParameters = webParameters => { if (!Object.prototype.hasOwnProperty.call(values[i], "style")) { return false; } + + if (!Object.prototype.hasOwnProperty.call(values[i], "params")) { + return false; + } + + for (let j = 0; j < REQUIRED_PARAMS.length; j += 1) { + if ( + !Object.prototype.hasOwnProperty.call( + values[i].params, + REQUIRED_PARAMS[j] + ) + ) { + return false; + } + } } return true; }; const generateWebParameters = mobileParameters => { + if (!mobileParameters) { + return undefined; + } + const { uiTakeover = false } = mobileParameters; return { @@ -259,6 +279,10 @@ export const displayHTMLContentInIframe = (settings, interact) => { webParameters = generateWebParameters(mobileParameters); } + if (!webParameters) { + return; + } + renderMessage(iframe, webParameters, container, overlay); }; diff --git a/test/unit/specs/components/Personalization/in-app-message-actions/actions/displayIframeContent.spec.js b/test/unit/specs/components/Personalization/in-app-message-actions/actions/displayIframeContent.spec.js index 0b055acd7..e03314eaa 100644 --- a/test/unit/specs/components/Personalization/in-app-message-actions/actions/displayIframeContent.spec.js +++ b/test/unit/specs/components/Personalization/in-app-message-actions/actions/displayIframeContent.spec.js @@ -330,7 +330,6 @@ describe("DOM Actions on Iframe", () => { it("should display HTML content in iframe with overlay using web parameters", () => { const settings = { - type: "custom", webParameters: { "alloy-overlay-container": { style: { @@ -344,7 +343,9 @@ describe("DOM Actions on Iframe", () => { backgroundColor: "#FFFFFF" }, params: { - enabled: true + enabled: true, + parentElement: "body", + insertionMethod: "appendChild" } }, "alloy-messaging-container": { @@ -364,6 +365,7 @@ describe("DOM Actions on Iframe", () => { height: "63vh" }, params: { + enabled: true, parentElement: "body", insertionMethod: "appendChild" } @@ -404,7 +406,9 @@ describe("DOM Actions on Iframe", () => { backgroundColor: "#FFFFFF" }, params: { - enabled: false + enabled: false, + parentElement: "body", + insertionMethod: "appendChild" } }, "alloy-messaging-container": { @@ -424,6 +428,7 @@ describe("DOM Actions on Iframe", () => { height: "63vh" }, params: { + enabled: true, parentElement: "body", insertionMethod: "appendChild" }