From 12f323ad4279ef9482ccfff592b5c5b5201a4403 Mon Sep 17 00:00:00 2001 From: mathuria Date: Tue, 25 Feb 2025 12:48:05 +0530 Subject: [PATCH] Remove v1 code --- unitylibs/core/steps/app-connector.js | 88 --- unitylibs/core/steps/upload-btn.js | 97 --- unitylibs/core/steps/upload-step.js | 68 --- .../workflow-photoshop/workflow-photoshop.css | 163 ------ .../workflow-photoshop/workflow-photoshop.js | 552 ------------------ unitylibs/core/workflow/workflow.js | 126 +--- unitylibs/scripts/utils.js | 119 ---- 7 files changed, 4 insertions(+), 1209 deletions(-) delete mode 100644 unitylibs/core/steps/app-connector.js delete mode 100644 unitylibs/core/steps/upload-btn.js delete mode 100644 unitylibs/core/steps/upload-step.js delete mode 100644 unitylibs/core/workflow/workflow-photoshop/workflow-photoshop.css delete mode 100644 unitylibs/core/workflow/workflow-photoshop/workflow-photoshop.js diff --git a/unitylibs/core/steps/app-connector.js b/unitylibs/core/steps/app-connector.js deleted file mode 100644 index a0854668..00000000 --- a/unitylibs/core/steps/app-connector.js +++ /dev/null @@ -1,88 +0,0 @@ -import { createActionBtn, createIntersectionObserver, getHeaders, getLocale } from '../../scripts/utils.js'; - -function getPreludeData(cfg) { - const dataObj = { - targetProduct: 'Photoshop', - payload: { - locale: getLocale(), - operations: [...cfg.preludeState.operations], - }, - }; - if(cfg.presentState.cache) { - dataObj.href = cfg.preludeState.href - dataObj.payload.finalAssetUrl = cfg.preludeState.finalAssetUrl; - } else { - dataObj.assetId = cfg.preludeState.assetId - dataObj.payload.finalAssetId = cfg.preludeState.finalAssetId; - } - if (cfg.presentState?.adjustments && cfg.presentState?.adjustments.modified) { - const imageAdjustment = { - name: 'imageAdjustment', - target: '', - hue: parseInt(cfg.presentState?.adjustments.hue.value, 10), - sat: parseInt(cfg.presentState?.adjustments.saturation.value, 10), - }; - dataObj.payload.operations.push(imageAdjustment); - } - return dataObj; -} - -async function continueInApp(cfg, appName, btnConfig) { - const { - apiKey, - connectorApiEndPoint, - refreshWidgetEvent, - targetEl, - unityEl, - unityWidget, - } = cfg; - const continuebtn = unityWidget.querySelector(`continue-in-${appName}`); - if (continuebtn) return continuebtn; - const btn = await createActionBtn(btnConfig, `continue-in-app continue-in-${appName}`, true, true); - btn.addEventListener('click', async (evt) => { - evt.preventDefault(); - const { showErrorToast } = await import('../../scripts/utils.js'); - cfg.continueRetrying = false; - if (cfg.scanResponseAfterRetries && cfg.scanResponseAfterRetries.status === 403) { - unityEl.dispatchEvent(new CustomEvent(refreshWidgetEvent)); - await showErrorToast(targetEl, unityEl, '.icon-error-acmp'); - return false; - } - const data = getPreludeData(cfg); - const connectorOptions = { - method: 'POST', - headers: getHeaders(apiKey), - body: JSON.stringify(data), - }; - const response = await fetch(connectorApiEndPoint, connectorOptions); - if (response.status !== 200) { - await showErrorToast(targetEl, unityEl, '.icon-error-request'); - return ''; - } - const { url } = await response.json(); - window.location.href = url; - return true; - }); - return btn; -} - -function resetAppConnector(cfg) { - const connectBtn = cfg.unityWidget.querySelector('.continue-in-app'); - connectBtn?.classList.remove('show'); -} - -export default async function initAppConnector(cfg, appName) { - const { unityEl, unityWidget, refreshWidgetEvent, interactiveSwitchEvent, targetEl } = cfg; - const isContinueEnabled = unityEl.querySelector('.icon-app-connector'); - if (!isContinueEnabled) return; - const btnConfig = isContinueEnabled.closest('li'); - const connectBtn = await continueInApp(cfg, appName, btnConfig); - unityWidget.querySelector('.unity-action-area').append(connectBtn); - unityEl.addEventListener(refreshWidgetEvent, () => { - connectBtn?.classList.remove('show'); - }); - unityEl.addEventListener(interactiveSwitchEvent, () => { - connectBtn?.classList.add('show'); - }); - createIntersectionObserver({ el: targetEl, callback: resetAppConnector, cfg }); -} diff --git a/unitylibs/core/steps/upload-btn.js b/unitylibs/core/steps/upload-btn.js deleted file mode 100644 index 5a35291a..00000000 --- a/unitylibs/core/steps/upload-btn.js +++ /dev/null @@ -1,97 +0,0 @@ -import { createTag, createActionBtn } from '../../scripts/utils.js'; - -const CONTAIN_OBJECT = 'contain-object'; -const MOBILE_GRAY_BG = 'mobile-gray-bg'; -const GRAY_BG = 'gray-bg'; -const FULL_HEIGHT = 'full-height'; -export const IMG_LANDSCAPE = 'img-landscape'; -export const IMG_PORTRAIT = 'img-portrait'; -export const IMG_REMOVE_BG = 'img-removebg'; - -export function resetClasses(img, targetEl) { - if (img.classList.contains(CONTAIN_OBJECT)) img.classList.remove(CONTAIN_OBJECT); - if (img.classList.contains(IMG_LANDSCAPE)) img.classList.remove(IMG_LANDSCAPE); - if (img.classList.contains(IMG_PORTRAIT)) img.classList.remove(IMG_PORTRAIT); - if (img.classList.contains(IMG_REMOVE_BG)) img.classList.remove(IMG_REMOVE_BG); - if (img.classList.contains(MOBILE_GRAY_BG)) img.classList.remove(MOBILE_GRAY_BG); - if (targetEl.classList.contains(GRAY_BG)) targetEl.classList.remove(GRAY_BG); -} - -export default async function createUpload(cfg, target, callback = null) { - const { refreshWidgetEvent, targetEl, unityEl } = cfg; - const li = unityEl.querySelector('.icon-upload').parentElement; - const a = await createActionBtn(li, 'show'); - const input = createTag('input', { class: 'file-upload', type: 'file', accept: 'image/png,image/jpg,image/jpeg', tabIndex: -1 }); - a.insertAdjacentElement('afterend', input); - input.addEventListener('change', async (e) => { - let flag = true; - const fileUpload = e.target || input; - const { default: showProgressCircle } = await import('../features/progress-circle/progress-circle.js'); - const { showErrorToast } = await import('../../scripts/utils.js'); - const file = fileUpload.files[0]; - if (!file) return; - if (['image/jpeg', 'image/png', 'image/jpg'].indexOf(file.type) == -1) { - await showErrorToast(targetEl, unityEl, '.icon-error-filetype'); - return; - } - const MAX_FILE_SIZE = 40000000; - if (file.size > MAX_FILE_SIZE) { - await showErrorToast(targetEl, unityEl, '.icon-error-filesize'); - return; - } - const objUrl = URL.createObjectURL(file); - resetClasses(target, targetEl); - target.src = objUrl; - target.onload = async () => { - cfg.uploadState.filetype = file.type; - cfg.isUpload = true; - if (callback && flag) { - flag = false; - try { - const targetElWidth = targetEl.offsetWidth; - const targetElHeight = targetEl.offsetHeight; - if (!target.classList.contains(CONTAIN_OBJECT)) { - target.classList.add(CONTAIN_OBJECT); - } - if (!target.classList.contains(MOBILE_GRAY_BG)) { - target.classList.add(MOBILE_GRAY_BG); - } - if (!targetEl.classList.contains(GRAY_BG)) targetEl.classList.add(GRAY_BG); - if (target.naturalWidth > targetElWidth) { - cfg.imgDisplay = 'landscape'; - if (!target.classList.contains(IMG_LANDSCAPE)) target.classList.add(IMG_LANDSCAPE); - if (target.classList.contains(FULL_HEIGHT)) target.classList.remove(FULL_HEIGHT); - } else { - cfg.imgDisplay = 'portrait'; - if (!target.classList.contains(IMG_PORTRAIT)) target.classList.add(IMG_PORTRAIT); - if (!target.classList.contains(FULL_HEIGHT)) target.classList.add(FULL_HEIGHT); - } - if (target.naturalWidth == targetElWidth && target.naturalHeight == targetElHeight) { - cfg.imgDisplay = ''; - resetClasses(target, targetEl); - } - showProgressCircle(targetEl); - await callback(cfg); - if (target.classList.contains(MOBILE_GRAY_BG)) target.classList.remove(MOBILE_GRAY_BG); - showProgressCircle(targetEl); - } catch (err) { - showProgressCircle(targetEl); - await showErrorToast(targetEl, unityEl, '.icon-error-request'); - } - } - const alertHolder = targetEl.querySelector('.alert-holder'); - if (alertHolder && alertHolder.style.display === 'flex') { - unityEl.dispatchEvent(new CustomEvent(refreshWidgetEvent)); - } - }; - target.onerror = async () => { - await showErrorToast(targetEl, unityEl, '.icon-error-request'); - }; - fileUpload.value = ''; - }); - a.addEventListener('keydown', (e) => { - if (e.key === 'Enter') input.click(); - }); - a.addEventListener('click', () => input.click()); - return a; -} diff --git a/unitylibs/core/steps/upload-step.js b/unitylibs/core/steps/upload-step.js deleted file mode 100644 index 83cfeac9..00000000 --- a/unitylibs/core/steps/upload-step.js +++ /dev/null @@ -1,68 +0,0 @@ -import { getHeaders } from '../../scripts/utils.js'; - -export async function getImageBlobData(url) { - return new Promise((res, rej) => { - const xhr = new XMLHttpRequest(); - xhr.open('GET', url); - xhr.responseType = 'blob'; - xhr.onload = () => { - if (xhr.status === 200) res(xhr.response); - else rej(xhr.status); - }; - xhr.send(); - }); -} - -async function uploadImgToUnity(cfg, storageUrl, id, blobData, fileType) { - const { targetEl, unityEl } = cfg; - const { showErrorToast } = await import('../../scripts/utils.js'); - const uploadOptions = { - method: 'PUT', - headers: { 'Content-Type': fileType }, - body: blobData, - }; - const response = await fetch(storageUrl, uploadOptions); - if (response.status !== 200) { - await showErrorToast(targetEl, unityEl, '.icon-error-request'); - return ''; - } - return id; -} - -function getFileType(cfg, imgUrl) { - if (imgUrl.startsWith('blob:')) return cfg.uploadState.filetype; - if (imgUrl.endsWith('.jpeg')) return 'image/jpeg'; - if (imgUrl.endsWith('.png')) return 'image/png'; - if (imgUrl.endsWith('.jpg')) return 'image/jpg'; - return ''; -} - -export async function uploadAsset(cfg, imgUrl) { - const { apiEndPoint, apiKey, targetEl, unityEl } = cfg; - const { showErrorToast } = await import('../../scripts/utils.js'); - const genIdOptions = { - method: 'POST', - headers: getHeaders(apiKey), - }; - const response = await fetch(`${apiEndPoint}/asset`, genIdOptions); - if (response.status !== 200) { - await showErrorToast(targetEl, unityEl, '.icon-error-request'); - return ''; - } - const { id, href } = await response.json(); - const blobData = await getImageBlobData(imgUrl); - const fileType = getFileType(cfg, imgUrl); - const assetId = await uploadImgToUnity(cfg, href, id, blobData, fileType); - return assetId; -} - -export async function scanImgForSafety(cfg, assetId) { - const { apiEndPoint, apiKey } = cfg; - const assetData = { assetId, targetProduct: 'Photoshop' }; - const imgScanOptions = { - method: 'POST', - headers: getHeaders(apiKey), - body: JSON.stringify(assetData), - }; - return fetch(`${apiEndPoint}/asset/finalize`, imgScanOptions); -} diff --git a/unitylibs/core/workflow/workflow-photoshop/workflow-photoshop.css b/unitylibs/core/workflow/workflow-photoshop/workflow-photoshop.css deleted file mode 100644 index bba81bc9..00000000 --- a/unitylibs/core/workflow/workflow-photoshop/workflow-photoshop.css +++ /dev/null @@ -1,163 +0,0 @@ -.unity-enabled .interactive-area .unity-option-area .changebg-options-tray { - display: none; - flex-direction: row; - padding: 8px; -} - -.unity-enabled .interactive-area .unity-option-area .changebg-options-tray.show { - display: flex; -} - -.unity-enabled .interactive-area .unity-option-area .changebg-options-tray .changebg-option { - border-radius: 4px; - cursor: pointer; - border: 3px solid transparent; - overflow: hidden; - position: relative; - top: 0; - left: 0; - object-fit: cover; - height: 67px; -} - -.unity-enabled .interactive-area .unity-option-area .changebg-options-tray .changebg-option:focus-visible { - outline: none; -} - -.unity-enabled .interactive-area .unity-option-area .adjustment-options-tray { - display: none; - flex-direction: column; - gap: 15px; - padding: 16px 16px 0; -} - -.unity-enabled .interactive-area .unity-option-area .adjustment-options-tray.show { - display: flex; -} - -.unity-enabled .interactive-area .unity-option-area .adjustment-options-tray .adjustment-container { - height: 2px; - border-radius: 1px; - margin: 7px 0; - position: relative; -} - -.unity-enabled .interactive-area .unity-option-area .adjustment-options-tray .adjustment-label { - font-size: var(--type-body-m-size); - line-height: var(--type-body-m-lh); -} - -.unity-enabled .interactive-area .unity-option-area .adjustment-options-tray .adjustment-container.hue { - background: linear-gradient(90deg, #E90B03 0%, #EF9100 9%, #FFE003 20.5%, #5AFE00 32.5%, #00FF84 43.5%, #00F1EF 53.5%, #001AFF 66.86%, #8700FC 77.17%, #FD00D6 89.5%, #FF0015 100%); -} - -.unity-enabled .interactive-area .unity-option-area .adjustment-options-tray .adjustment-container.saturation { - background: linear-gradient(90deg, #000 0%, #F20000 100%); -} - -.unity-enabled .interactive-area .unity-option-area .adjustment-options-tray .adjustment-slider { - width: 100%; - opacity: 0; - position: absolute; - top: -7px; - z-index: 1; - margin: 0; -} - -.unity-enabled .interactive-area .unity-option-area .adjustment-options-tray .adjustment-slider::-webkit-slider-thumb { - height: 20px; - width: 20px; - position: relative; - border-radius: 50%; - appearance: none; - background: transparent; - cursor: grab; - z-index: 2; -} - -.unity-enabled .interactive-area .unity-option-area .adjustment-options-tray .adjustment-circle { - position: absolute; - block-size: 16px; - inline-size: 16px; - background-color: #A2A2A2; - border-radius: 50%; - top: -7px; - inset-block-start: 50%; - inset-inline-start: 50%; - transform: translate(-50%, -50%); -} - -.unity-enabled .interactive-area .unity-option-area .adjustment-options-tray .adjustment-circle .analytics-content { - display: none; -} - -.unity-enabled .interactive-area .unity-option-area .changebg-options-tray .changebg-option:focus-visible, -.unity-enabled .interactive-area .unity-option-area .changebg-options-tray .changebg-option:hover { - border: 3px solid var(--highlight-blue); -} - -@media screen and (max-width: 600px) { - .unity-enabled .interactive-area .unity-option-area .changebg-options-tray { - padding: 5px 5px 0; - gap: 9px; - border-radius: 8px 8px 0 0; - align-items: center; - justify-content: center; - } - - .unity-enabled .interactive-area .unity-option-area .changebg-options-tray .changebg-option { - width: 100%; - max-width: 93px; - } - - .unity-enabled .interactive-area .unity-option-area .changebg-options-tray .changebg-option img { - width: 100%; - height: 67px; - min-height: 67px; - max-height: 67px; - position: relative; - top: 0; - left: 0; - object-fit: cover; - } - - .unity-enabled .interactive-area .unity-action-btn:active .btn-text, - .unity-enabled .interactive-area .unity-action-btn:active .btn-icon svg path { - color: var(--highlight-blue); - fill: var(--highlight-blue); - } -} - -@media screen and (min-width: 600px) and (min-width: 1200px) { - .aside.split.unity-enabled .split-image img { - position: relative; - } -} - -@media screen and (min-width: 600px) { - .unity-enabled .interactive-area .unity-option-area .changebg-options-tray { - gap: 2px; - width: fit-content; - border-radius: 8px; - padding: 5px; - } - - .unity-enabled .interactive-area .unity-option-area .changebg-options-tray img { - height: 67px; - min-height: 67px; - max-height: 67px; - width: 67px; - min-width: 67px; - max-width: 67px; - } - - .unity-enabled .interactive-area .unity-option-area .adjustment-options-tray { - padding: 8px 16px; - width: 212px; - min-width: 212px; - } - - .unity-enabled .interactive-area .unity-option-area .adjustment-options-tray .adjustment-label { - font-weight: bold; - } -} diff --git a/unitylibs/core/workflow/workflow-photoshop/workflow-photoshop.js b/unitylibs/core/workflow/workflow-photoshop/workflow-photoshop.js deleted file mode 100644 index be1ee242..00000000 --- a/unitylibs/core/workflow/workflow-photoshop/workflow-photoshop.js +++ /dev/null @@ -1,552 +0,0 @@ -import { - createTag, - getUnityLibs, - getHeaders, - loadImg, - createActionBtn, - loadSvg, - createIntersectionObserver, - priorityLoad, - getLibs, - delay, - updateQueryParameter -} from '../../../scripts/utils.js'; - -const miloLibs = getLibs('/libs'); -const { decorateDefaultLinkAnalytics } = await import(`${miloLibs}/martech/attributes.js`); -const cachedId = 'noop_string'; - -function resetSliders(unityWidget) { - const adjustmentCircles = unityWidget.querySelectorAll('.adjustment-circle'); - adjustmentCircles.forEach((c) => { c.style = ''; }); -} - -function addOrUpdateOperation(array, keyToCheck, valueToCheck, keyToUpdate, newValue, newObject) { - const existingObject = array.find((obj) => obj[keyToCheck] === valueToCheck); - if (existingObject) { - existingObject[keyToUpdate] = newValue; - } else { - array.push(newObject); - } -} - -function resetWorkflowState(cfg) { - cfg.presentState = { - cache: cfg.cacheDefault, - activeIdx: cfg.isUpload ? 0 : -1, - removeBgState: { - assetId: null, - assetUrl: null, - }, - changeBgState: {}, - adjustments: {}, - }; - cfg.preludeState = { assetId: null, operations: [] }; - const img = cfg.targetEl.querySelector(':scope > picture img'); - img.style.filter = ''; - resetSliders(cfg.unityWidget); -} - -function toggleDisplay(domEl) { - if (domEl.classList.contains('show')) domEl.classList.remove('show'); - else domEl.classList.add('show'); -} - -async function addProductIcon(cfg) { - const { unityEl, unityWidget, targetEl, refreshWidgetEvent } = cfg; - cfg.refreshEnabled = false; - const refreshCfg = unityEl.querySelector('.icon-product-icon'); - if (!refreshCfg) return; - const [prodIcon, refreshIcon] = refreshCfg.closest('li').querySelectorAll('img[src*=".svg"]'); - const unityOrigin = getUnityLibs().split('/unitylibs')[0]; - prodIcon.src = `${unityOrigin}${new URL(prodIcon.src).pathname}`; - const iconHolder = createTag('div', { class: 'widget-product-icon show' }, prodIcon); - const refreshSvg = await loadSvg(`${unityOrigin}${new URL(refreshIcon.src).pathname}`); - const refreshAnalyics = createTag('div', { class: 'widget-refresh-text' }, 'Restart'); - const refreshHolder = createTag('a', { href: '#', class: 'widget-refresh-button' }, refreshSvg); - refreshHolder.append(refreshAnalyics); - await loadImg(prodIcon); - unityWidget.querySelector('.unity-action-area').append(iconHolder); - if (!refreshIcon) return; - cfg.refreshEnabled = true; - const mobileRefreshHolder = refreshHolder.cloneNode(true); - [refreshHolder, mobileRefreshHolder].forEach((el) => { - el.addEventListener('click', (evt) => { - evt.preventDefault(); - unityEl.dispatchEvent(new CustomEvent(refreshWidgetEvent)); - }); - }); - unityWidget.querySelector('.unity-action-area').append(refreshHolder); - targetEl.append(mobileRefreshHolder); -} - -async function handleEvent(cfg, eventHandler) { - const { targetEl, unityEl } = cfg; - const { default: showProgressCircle } = await import('../../features/progress-circle/progress-circle.js'); - const { showErrorToast } = await import('../../../scripts/utils.js'); - showProgressCircle(targetEl); - try { - await eventHandler(); - } catch (e) { - await showErrorToast(targetEl, unityEl, '.icon-error-request'); - } finally { - showProgressCircle(targetEl); - } -} - -async function updateImgClasses(cfg, img) { - const { imgDisplay } = cfg; - if (imgDisplay === 'landscape' || imgDisplay === 'portrait') { - const { - IMG_LANDSCAPE, - IMG_PORTRAIT, - IMG_REMOVE_BG, - } = await import('../../steps/upload-btn.js'); - if (cfg.imgDisplay === 'landscape') { - if (img.classList.contains(IMG_LANDSCAPE)) img.classList.remove(IMG_LANDSCAPE); - } else if (cfg.imgDisplay === 'portrait') { - if (img.classList.contains(IMG_PORTRAIT)) img.classList.remove(IMG_PORTRAIT); - } - if (!img.classList.contains(IMG_REMOVE_BG)) img.classList.add(IMG_REMOVE_BG); - } -} - -function checkImgModified(hostname) { - let isModified = false; - try { - const pageUrlObject = new URL(window.location.href); - isModified = hostname !== pageUrlObject.hostname; - } catch (e) { - return ''; - } - return isModified; -} - -async function removeBgHandler(cfg, changeDisplay = true, cachedImg=null) { - const { - apiEndPoint, - apiKey, - interactiveSwitchEvent, - refreshWidgetEvent, - targetEl, - unityEl, - } = cfg; - const { showErrorToast } = await import('../../../scripts/utils.js'); - const { endpoint } = cfg.wfDetail.removebg; - const img = targetEl.querySelector('picture img'); - const hasExec = cfg.presentState.removeBgState.srcUrl; - if (changeDisplay - && hasExec - && !(img.src.startsWith(cfg.presentState.removeBgState.srcUrl))) { - cfg.presentState.removeBgState.assetId = null; - cfg.presentState.removeBgState.srcUrl = null; - cfg.presentState.changeBgState = {}; - cfg.presentState.adjustments = {}; - cfg.presentState.assetId = null; - cfg.preludeState.operations = []; - if(cfg.preludeState.href) { - cfg.preludeState.href = null; - } - } - if(cfg.presentState.cache && cachedImg) { - await delay(500); - cfg.presentState.removeBgState.assetUrl=cachedImg.src; - cfg.presentState.removeBgState.assetId = cachedId; - cfg.preludeState.href = updateQueryParameter(img.src); - cfg.preludeState.finalAssetUrl = updateQueryParameter(cachedImg.src); - } - const { srcUrl, assetUrl } = cfg.presentState.removeBgState; - const urlIsValid = assetUrl ? await fetch(assetUrl) : null; - if (cfg.presentState.removeBgState.assetId && urlIsValid?.status === 200) { - if (changeDisplay) { - img.src = cfg.presentState.removeBgState.assetUrl; - cfg.preludeState.operations.push({ name: 'removeBackground' }); - await loadImg(img); - unityEl.dispatchEvent(new CustomEvent(interactiveSwitchEvent)); - } - return false; - } - const { hostname, origin, pathname } = new URL(img.src); - const imgUrl = srcUrl || (img.src.startsWith('blob:') ? img.src : `${origin}${pathname}`); - const isImgModified = checkImgModified(hostname); - cfg.presentState.removeBgState.srcUrl = imgUrl; - const { uploadAsset } = await import('../../steps/upload-step.js'); - const id = await uploadAsset(cfg, imgUrl); - if (!id) { - await showErrorToast(targetEl, unityEl, '.icon-error-request'); - return false; - } - if (isImgModified) { - const { scanImgForSafety } = await import('../../steps/upload-step.js'); - let scanResponse = await scanImgForSafety(cfg, id); - if (scanResponse.status === 403) { - unityEl.dispatchEvent(new CustomEvent(refreshWidgetEvent)); - await showErrorToast(targetEl, unityEl, '.icon-error-acmp'); - return false; - } - if (scanResponse.status === 429 - || (scanResponse.status >= 500 && scanResponse.status < 600)) { - const { retryRequestUntilProductRedirect } = await import('../../../scripts/utils.js'); - scanResponse = await retryRequestUntilProductRedirect(cfg, () => scanImgForSafety(cfg, id)); - } - } - cfg.preludeState.assetId = id; - const removeBgOptions = { - method: 'POST', - headers: getHeaders(apiKey), - body: `{"surfaceId":"Unity","assets":[{"id": "${id}"}]}`, - }; - const response = await fetch(`${apiEndPoint}/${endpoint}`, removeBgOptions); - if (response.status !== 200) { - await showErrorToast(targetEl, unityEl, '.icon-error-request'); - return false; - } - const { outputUrl } = await response.json(); - const opId = new URL(outputUrl).pathname.split('/').pop(); - cfg.preludeState.finalAssetId = opId; - cfg.presentState.removeBgState.assetId = opId; - cfg.presentState.removeBgState.assetUrl = outputUrl; - cfg.preludeState.operations.push({ name: 'removeBackground' }); - if (!changeDisplay) return true; - await updateImgClasses(cfg, img); - img.src = outputUrl; - await loadImg(img); - unityEl.dispatchEvent(new CustomEvent(interactiveSwitchEvent)); - return true; -} - -async function removebg(cfg, featureName) { - const { wfDetail, unityWidget } = cfg; - const removebgBtn = unityWidget.querySelector('.ps-action-btn.removebg-button'); - if (removebgBtn) return removebgBtn; - const { authorCfg } = wfDetail[featureName]; - const btn = await createActionBtn(authorCfg, 'ps-action-btn removebg-button show'); - btn.addEventListener('click', async (evt) => { - evt.preventDefault(); - handleEvent(cfg, () => removeBgHandler(cfg, true, authorCfg.querySelectorAll('picture img')[1])); - }); - return btn; -} - -async function changeBgHandler(cfg, selectedUrl = null, refreshState = true, cachedImg = null) { - if (refreshState) resetWorkflowState(); - const { - apiEndPoint, - apiKey, - targetEl, - unityWidget, - unityEl, - interactiveSwitchEvent, - } = cfg; - const { showErrorToast } = await import('../../../scripts/utils.js'); - const { endpoint } = cfg.wfDetail.changebg; - const unityRetriggered = await removeBgHandler(cfg, false); - const img = targetEl.querySelector('picture img'); - const bgImg = selectedUrl || unityWidget.querySelector('.unity-option-area .changebg-options-tray img').dataset.backgroundImg; - const { origin, pathname } = new URL(bgImg); - const bgImgUrl = `${origin}${pathname}`; - if(cfg.presentState.cache && cachedImg) { - await delay(500) - img.src = cachedImg.src; - await loadImg(img); - const bgImgUrlUpdated = updateQueryParameter(bgImgUrl); - addOrUpdateOperation(cfg.preludeState.operations, 'name', 'changeBackground', 'hrefs', [bgImgUrlUpdated], { name: 'changeBackground', hrefs: [bgImgUrlUpdated] }); - cfg.preludeState.finalAssetUrl = updateQueryParameter(cachedImg.src); - unityEl.dispatchEvent(new CustomEvent(interactiveSwitchEvent)); - return; - } - const fgId = cfg.presentState.removeBgState.assetId; - const { uploadAsset } = await import('../../steps/upload-step.js'); - const bgId = await uploadAsset(cfg, bgImgUrl); - if (!unityRetriggered && cfg.presentState.changeBgState[bgImgUrl]?.assetId) { - img.src = cfg.presentState.changeBgState[bgImgUrl].assetUrl; - await loadImg(img); - addOrUpdateOperation(cfg.preludeState.operations, 'name', 'changeBackground', 'assetIds', [bgId], { name: 'changeBackground', assetIds: [bgId] }); - unityEl.dispatchEvent(new CustomEvent(interactiveSwitchEvent)); - return; - } - const changeBgOptions = { - method: 'POST', - headers: getHeaders(apiKey), - body: `{ - "assets": [{ "id": "${fgId}" },{ "id": "${bgId}" }], - "metadata": { - "foregroundImageId": "${fgId}", - "backgroundImageId": "${bgId}" - } - }`, - }; - const response = await fetch(`${apiEndPoint}/${endpoint}`, changeBgOptions); - if (response.status !== 200) { - await showErrorToast(targetEl, unityEl, '.icon-error-request'); - return; - } - const { outputUrl } = await response.json(); - const changeBgId = new URL(outputUrl).pathname.split('/').pop(); - cfg.presentState.changeBgState[bgImgUrl] = {}; - cfg.presentState.changeBgState[bgImgUrl].assetId = changeBgId; - cfg.presentState.changeBgState[bgImgUrl].assetUrl = outputUrl; - cfg.preludeState.finalAssetId = changeBgId; - addOrUpdateOperation(cfg.preludeState.operations, 'name', 'changeBackground', 'assetIds', [bgId], { name: 'changeBackground', assetIds: [bgId] }); - img.src = outputUrl; - await loadImg(img); - if (!img.classList.contains('mobile-gray-bg')) img.classList.add('mobile-gray-bg'); - unityEl.dispatchEvent(new CustomEvent(interactiveSwitchEvent)); -} - -function updateQueryParam(url, params) { - const parsedUrl = new URL(url); - Object.entries(params).forEach(([key, value]) => { - parsedUrl.searchParams.set(key, value); - }); - return parsedUrl; -} - -async function changebg(cfg, featureName) { - const { unityWidget, wfDetail } = cfg; - const { authorCfg } = wfDetail[featureName]; - const changebgBtn = unityWidget.querySelector('.ps-action-btn.changebg-button'); - if (changebgBtn) return changebgBtn; - const btn = await createActionBtn(authorCfg, 'ps-action-btn changebg-button subnav-active show'); - btn.classList.add('focus'); - btn.dataset.optionsTray = 'changebg-options-tray'; - const bgSelectorTray = createTag('div', { class: 'changebg-options-tray show' }); - const bgOptions = authorCfg.querySelectorAll(':scope>ul>li'); - const thumbnailSrc = []; - [...bgOptions].forEach((o) => { - let thumbnail = null; - let bgImg = null; - let imgs = o.querySelectorAll('img'); - bgImg = imgs[0] - thumbnail = bgImg; - thumbnail.dataset.backgroundImg = bgImg.src; - thumbnail.setAttribute('src', updateQueryParam(bgImg.src, { format: 'webply', width: '68', height: '68' })); - thumbnailSrc.push(thumbnail.getAttribute('src')); - const a = createTag('a', { href: '#', class: 'changebg-option' }, thumbnail); - bgSelectorTray.append(a); - a.addEventListener('click', async (evt) => { - evt.preventDefault(); - handleEvent(cfg, () => changeBgHandler(cfg, bgImg.src, false, imgs[1])); - }); - }); - priorityLoad(thumbnailSrc); - unityWidget.querySelector('.unity-option-area').append(bgSelectorTray); - btn.addEventListener('click', (evt) => { - evt.preventDefault(); - if (btn.classList.contains('subnav-active')) btn.classList.remove('subnav-active'); - else btn.classList.add('subnav-active'); - toggleDisplay(unityWidget.querySelector('.unity-option-area .changebg-options-tray')); - if (btn.classList.contains('focus')) { - btn.classList.remove('focus'); - } else { - btn.classList.add('focus'); - } - }); - return btn; -} - -function updateAdjustment(cfg, cssFilter, propertyName, value) { - const filterValue = cssFilter.replace('inputValue', value); - cfg.presentState.adjustments[propertyName] = { value, filterValue }; -} - -function createSlider(cfg, tray, propertyName, label, cssFilter, valObj) { - const { targetEl } = cfg; - const { minVal, maxVal, zeroVal } = valObj; - const actionDiv = createTag('div', { class: 'adjustment-option' }); - const actionLabel = createTag('label', { class: 'adjustment-label' }, label); - const actionSliderDiv = createTag('div', { class: `adjustment-container ${propertyName}` }); - const actionSliderInput = createTag('input', { - type: 'range', - min: minVal, - max: maxVal, - value: zeroVal, - class: `adjustment-slider ${propertyName}`, - }); - updateAdjustment(cfg, cssFilter, propertyName, zeroVal); - const actionAnalytics = createTag('div', { class: 'analytics-content' }, `Adjust ${label} slider`); - const actionSliderCircle = createTag('a', { href: '#', class: `adjustment-circle ${propertyName}` }, actionAnalytics); - actionSliderDiv.append(actionSliderInput, actionSliderCircle); - actionDiv.append(actionLabel, actionSliderDiv); - const isRtl = document.dir === 'rtl'; - actionSliderInput.addEventListener('input', () => { - const { value } = actionSliderInput; - const centerOffset = (value - minVal) / (maxVal - minVal); - const moveCircle = isRtl ? centerOffset * 94 - 4 : 3 + centerOffset * 94; - actionSliderCircle.style[isRtl ? 'right' : 'left'] = `${moveCircle}%`; - actionSliderCircle.style[isRtl ? 'left' : 'right'] = ''; - const img = targetEl.querySelector(':scope > picture img'); - updateAdjustment(cfg, cssFilter, propertyName, value); - cfg.presentState.adjustments.modified = true; - const imgFilters = Object.keys(cfg.presentState.adjustments); - img.style.filter = ''; - imgFilters.forEach((f) => { - img.style.filter += `${cfg.presentState.adjustments[f].filterValue} `; - }); - }); - actionSliderInput.addEventListener('change', () => { - actionSliderCircle.click(); - }); - actionSliderCircle.addEventListener('click', (evt) => { - evt.preventDefault(); - }); - tray.append(actionDiv); -} - -async function changeAdjustments(cfg, featureName) { - const { unityWidget, wfDetail, targetEl } = cfg; - const { authorCfg } = wfDetail[featureName]; - const adjustmentBtn = unityWidget.querySelector('.ps-action-btn.adjustment-button'); - const hueCssFilter = 'hue-rotate(inputValuedeg)'; - const saturationCssFilter = 'saturate(inputValue%)'; - const hueZeroVal = 0; - const saturationZeroVal = 100; - if (adjustmentBtn) { - const img = targetEl.querySelector(':scope > picture img'); - img.style.filter = ''; - updateAdjustment(cfg, hueCssFilter, 'hue', hueZeroVal); - updateAdjustment(cfg, saturationCssFilter, 'saturation', saturationZeroVal); - return adjustmentBtn; - } - const btn = await createActionBtn(authorCfg, 'ps-action-btn adjustment-button subnav-active show'); - btn.classList.add('focus'); - btn.dataset.optionsTray = 'adjustment-options-tray'; - const sliderTray = createTag('div', { class: 'adjustment-options-tray show' }); - const sliderOptions = authorCfg.querySelectorAll(':scope > ul li'); - [...sliderOptions].forEach((o) => { - let iconName = null; - const psAction = o.querySelector(':scope > .icon'); - [...psAction.classList].forEach((cn) => { if (cn.match('icon-')) iconName = cn; }); - const [, actionName] = iconName.split('-'); - switch (actionName) { - case 'hue': - createSlider(cfg, sliderTray, 'hue', o.innerText, hueCssFilter, { minVal: -180, maxVal: 180, zeroVal: hueZeroVal }); - break; - case 'saturation': - createSlider(cfg, sliderTray, 'saturation', o.innerText, saturationCssFilter, { minVal: 0, maxVal: 300, zeroVal: saturationZeroVal }); - break; - default: - break; - } - }); - unityWidget.querySelector('.unity-option-area').append(sliderTray); - btn.addEventListener('click', (evt) => { - evt.preventDefault(); - if (btn.classList.contains('subnav-active')) btn.classList.remove('subnav-active'); - else btn.classList.add('subnav-active'); - toggleDisplay(unityWidget.querySelector('.unity-option-area .adjustment-options-tray')); - if (btn.classList.contains('focus')) { - btn.classList.remove('focus'); - } else { - btn.classList.add('focus'); - } - }); - return btn; -} - -function showFeatureButton(unityWidget, prevBtn, currBtn) { - if (!prevBtn) { - unityWidget.querySelector('.unity-action-area').append(currBtn); - } else { - prevBtn.insertAdjacentElement('afterend', currBtn); - const prevOptionTray = prevBtn?.dataset.optionsTray; - unityWidget.querySelector(`.unity-option-area .${prevOptionTray}`)?.classList.remove('show'); - prevBtn.classList.remove('show'); - } - const currOptionTray = currBtn.dataset.optionsTray; - unityWidget.querySelector(`.unity-option-area .${currOptionTray}`)?.classList.add('show'); - currBtn.classList.add('show'); -} - -async function changeVisibleFeature(cfg) { - const { unityWidget, enabledFeatures } = cfg; - if (cfg.presentState.activeIdx + 1 === enabledFeatures.length) return; - cfg.presentState.activeIdx += 1; - const featureName = enabledFeatures[cfg.presentState.activeIdx]; - let actionBtn = null; - switch (featureName) { - case 'removebg': - actionBtn = await removebg(cfg, featureName); - break; - case 'changebg': - actionBtn = await changebg(cfg, featureName); - break; - case 'slider': - actionBtn = await changeAdjustments(cfg, featureName); - break; - default: - break; - } - const prevActionBtn = unityWidget.querySelector('.ps-action-btn.show'); - if (prevActionBtn === actionBtn) return; - showFeatureButton(unityWidget, prevActionBtn, actionBtn); -} - -async function resetWidgetState(cfg) { - const { unityWidget, unityEl, targetEl } = cfg; - cfg.presentState.activeIdx = -1; - cfg.presentState.cache = cfg.cacheDefault; - cfg.preludeState.operations = []; - cfg.isUpload = false; - cfg.imgDisplay = ''; - const initImg = unityEl.querySelector(':scope picture img'); - const img = targetEl.querySelector(':scope > picture img'); - img.src = initImg.src; - img.style.filter = ''; - await changeVisibleFeature(cfg); - unityWidget.querySelector('.widget-product-icon')?.classList.add('show'); - unityWidget.querySelector('.widget-refresh-button').classList.remove('show'); - targetEl.querySelector(':scope > .widget-refresh-button').classList.remove('show'); - const { resetClasses } = await import('../../steps/upload-btn.js'); - resetClasses(img, targetEl); - resetSliders(unityWidget); - await loadImg(img); -} - -async function switchProdIcon(cfg, forceRefresh = true) { - const { unityWidget, refreshEnabled, targetEl } = cfg; - const iconHolder = unityWidget.querySelector('.widget-product-icon'); - if (!(refreshEnabled)) return; - if (forceRefresh) { - await resetWidgetState(cfg); - return; - } - iconHolder?.classList.remove('show'); - unityWidget.querySelector('.widget-refresh-button').classList.add('show'); - targetEl.querySelector(':scope > .widget-refresh-button').classList.add('show'); -} - -async function uploadCallback(cfg) { - const { enabledFeatures } = cfg; - resetWorkflowState(cfg); - cfg.presentState.cache = false; - if (enabledFeatures.length === 1) return; - await removeBgHandler(cfg); - cfg.isUpload = false; -} - -export default async function init(cfg) { - const { targetEl, unityEl, unityWidget, interactiveSwitchEvent, refreshWidgetEvent } = cfg; - //check if caching is enabled - const cached = !!cfg.wfDetail?.removebg?.authorCfg?.querySelectorAll('picture img')[1]; - cfg.cacheDefault = cached; - resetWorkflowState(cfg); - await addProductIcon(cfg); - await changeVisibleFeature(cfg); - const img = cfg.targetEl.querySelector('picture img'); - const { default: createUpload } = await import('../../steps/upload-btn.js'); - const uploadBtn = await createUpload(cfg, img, uploadCallback); - unityWidget.querySelector('.unity-action-area').append(uploadBtn); - const { default: initAppConnector } = await import('../../steps/app-connector.js'); - await initAppConnector(cfg, 'photoshop'); - await decorateDefaultLinkAnalytics(unityWidget); - unityEl.addEventListener(interactiveSwitchEvent, async () => { - await changeVisibleFeature(cfg); - await switchProdIcon(cfg, false); - await decorateDefaultLinkAnalytics(unityWidget); - }); - unityEl.addEventListener(refreshWidgetEvent, async () => { - await switchProdIcon(cfg, true); - }); - createIntersectionObserver({ el: targetEl, callback: switchProdIcon, cfg }); -} diff --git a/unitylibs/core/workflow/workflow.js b/unitylibs/core/workflow/workflow.js index 4b690eef..a1960b81 100644 --- a/unitylibs/core/workflow/workflow.js +++ b/unitylibs/core/workflow/workflow.js @@ -1,6 +1,5 @@ import { createTag, - loadStyle, setUnityLibs, getUnityLibs, unityConfig, @@ -9,106 +8,6 @@ import { priorityLoad, } from '../../scripts/utils.js'; -export function getImgSrc(pic) { - const viewport = defineDeviceByScreenSize(); - let source = ''; - if (viewport === 'MOBILE') source = pic.querySelector('source[type="image/webp"]:not([media])'); - else source = pic.querySelector('source[type="image/webp"][media]'); - return source.srcset; -} - -function checkRenderStatus(targetBlock, res, rej, etime, rtime) { - if (etime > 20000) { rej(); return; } - if (targetBlock.querySelector('.text') && targetBlock.querySelector('.asset, .image')) res(); - else setTimeout(() => checkRenderStatus(targetBlock, res, rej, etime + rtime), rtime); -} - -function intEnbReendered(targetBlock) { - return new Promise((res, rej) => { - try { - checkRenderStatus(targetBlock, res, rej, 0, 100); - } catch (err) { rej(); } - }); -} - -function createInteractiveArea(el, pic) { - const iArea = createTag('div', { class: 'interactive-area' }); - const iWidget = createTag('div', { class: 'unity-widget decorating' }); - const unityaa = createTag('div', { class: 'unity-action-area' }); - const unityoa = createTag('div', { class: 'unity-option-area' }); - iWidget.append(unityoa, unityaa); - pic.querySelector('img').src = getImgSrc(pic); - [...pic.querySelectorAll('source')].forEach((s) => s.remove()); - const newPic = pic.cloneNode(true); - const p = createTag('p', {}, newPic); - el.querySelector(':scope > div > div').prepend(p); - iArea.append(pic, iWidget); - if (el.classList.contains('light')) iArea.classList.add('light'); - else iArea.classList.add('dark'); - return [iArea, iWidget]; -} - -async function getTargetArea(el) { - const metadataSec = el.closest('.section'); - const intEnb = metadataSec.querySelector('.marquee, .aside'); - try { - intEnb.classList.add('unity-enabled'); - await intEnbReendered(intEnb); - } catch (err) { return null; } - if (el.classList.contains('mobile-image-bottom')) intEnb.classList.add('mobile-image-bottom'); - const asset = intEnb.querySelector('.asset picture, .image picture'); - const container = asset.closest('p'); - const [iArea, iWidget] = createInteractiveArea(el, asset); - const assetArea = intEnb.querySelector('.asset, .image'); - if (container) container.replaceWith(iArea); - else assetArea.append(iArea); - return [iArea, iWidget]; -} - -function getEnabledFeatures(unityEl, wfDetail) { - const enabledFeatures = []; - const supportedFeatures = Object.keys(wfDetail); - const configuredFeatures = unityEl.querySelectorAll(':scope ul > li > span.icon'); - configuredFeatures.forEach((cf) => { - const cfName = [...cf.classList].find((cn) => cn.match('icon-')); - if (!cfName) return; - const fn = cfName.split('-')[1]; - const isEnabled = supportedFeatures.indexOf(fn); - if (isEnabled > -1) { - enabledFeatures.push(fn); - wfDetail[fn].authorCfg = cf.closest('li'); - } - }); - return enabledFeatures; -} - -function getWorkFlowInformation(el) { - let wfName = ''; - const workflowCfg = { - 'workflow-photoshop': { - removebg: { endpoint: 'providers/PhotoshopRemoveBackground' }, - changebg: { endpoint: 'providers/PhotoshopChangeBackground' }, - slider: {}, - }, - 'workflow-acrobat': {}, - }; - [...el.classList].forEach((cn) => { if (cn.match('workflow-')) wfName = cn; }); - if (!wfName || !workflowCfg[wfName]) return []; - return [wfName, workflowCfg[wfName]]; -} - -async function initWorkflow(cfg) { - loadStyle(`${getUnityLibs()}/core/workflow/${cfg.wfName}/${cfg.wfName}.css`); - const { default: wfinit } = await import(`./${cfg.wfName}/${cfg.wfName}.js`); - await wfinit(cfg); - cfg.unityWidget?.classList.remove('decorating'); - const actionBtn = cfg.unityWidget.querySelector('.unity-action-btn'); - actionBtn?.classList.add('animate-btn'); - cfg.unityWidget.addEventListener('mouseover', () => { - actionBtn?.classList.remove('animate-btn'); - }, { once: true }); -} - class WfInitiator { constructor() { this.el = null; @@ -314,32 +213,15 @@ class WfInitiator { } } -export default async function init(el, project = 'unity', unityLibs = '/unitylibs', unityVersion = 'v1', langRegion = 'us', langCode = 'en') { +export default async function init(el, project = 'unity', unityLibs = '/unitylibs', unityVersion = 'v2', langRegion = 'us', langCode = 'en') { let uv = new URLSearchParams(window.location.search).get('unityversion') || unityVersion; - if (el.classList.contains('workflow-ai')) uv = 'v2'; //This line will be removed once CC moves to unity V2 const { imsClientId } = getConfig(); if (imsClientId) unityConfig.apiKey = imsClientId; setUnityLibs(unityLibs, project); switch (uv) { - case 'v1': { - const [targetBlock, unityWidget] = await getTargetArea(el); - if (!targetBlock) return; - const [wfName, wfDetail] = getWorkFlowInformation(el); - if (!wfName || !wfDetail) return; - const enabledFeatures = getEnabledFeatures(el, wfDetail); - if (!enabledFeatures) return; - const wfConfig = { - unityEl: el, - targetEl: targetBlock, - unityWidget, - wfName, - wfDetail, - enabledFeatures, - uploadState: { }, - ...unityConfig, - }; - await initWorkflow(wfConfig); - } + case 'v1': + // deprecated + el.remove(); break; case 'v2': await new WfInitiator().init(el, project, unityLibs, langRegion, langCode); diff --git a/unitylibs/scripts/utils.js b/unitylibs/scripts/utils.js index 6053461f..c3289c4a 100644 --- a/unitylibs/scripts/utils.js +++ b/unitylibs/scripts/utils.js @@ -67,33 +67,6 @@ export function getLocale() { return currLocale ? currLocale : 'us'; } -export async function loadSvg(src) { - try { - const res = await fetch(src, { mode: 'no-cors' }); - if (!res.status === 200) return null; - const svg = await res.text(); - return svg; - } catch (e) { - return ''; - } -} - -export async function loadSvgs(svgs) { - const promiseArr = []; - [...svgs].forEach((svg) => { - promiseArr.push( - fetch(svg.src) - .then((res) => { - if (res.ok) return res.text(); - else throw new Error('Could not fetch SVG'); - }) - .then((txt) => { svg.parentElement.innerHTML = txt; }) - .catch((e) => { svg.remove(); }), - ); - }); - await Promise.all(promiseArr); -} - export function loadImg(img) { return new Promise((res) => { img.loading = 'eager'; @@ -106,27 +79,6 @@ export function loadImg(img) { }); } -export async function createActionBtn(btnCfg, btnClass, iconAsImg = false, swapOrder = false) { - const txt = btnCfg.innerText; - const img = btnCfg.querySelector('img[src*=".svg"]'); - const actionBtn = createTag('a', { href: '#', class: `unity-action-btn ${btnClass}` }); - if (img) { - let btnImg = null; - const { pathname } = new URL(img.src); - const libSrcPath = `${getUnityLibs().split('/unitylibs')[0]}${pathname}`; - if (iconAsImg) btnImg = createTag('img', { src: libSrcPath }); - else btnImg = await loadSvg(libSrcPath); - const btnIcon = createTag('div', { class: 'btn-icon' }, btnImg); - actionBtn.append(btnIcon); - } - if (txt) { - const btnTxt = createTag('div', { class: 'btn-text' }, txt.split('\n')[0].trim()); - if (swapOrder) actionBtn.prepend(btnTxt); - else actionBtn.append(btnTxt); - } - return actionBtn; -} - export async function priorityLoad(parr) { const promiseArr = []; parr.forEach((p) => { @@ -143,76 +95,6 @@ export async function priorityLoad(parr) { return await Promise.all(promiseArr); } -async function createErrorToast() { - const [alertImg, closeImg] = await Promise.all([ - fetch(`${getUnityLibs()}/img/icons/alert.svg`).then((res) => res.text()), - fetch(`${getUnityLibs()}/img/icons/close.svg`).then((res) => res.text()), - ]); - const errholder = createTag('div', { class: 'alert-holder' }); - const errdom = createTag('div', { class: 'alert-toast' }); - const alertContent = createTag('div', { class: 'alert-content' }); - const alertIcon = createTag('div', { class: 'alert-icon' }); - const alertText = createTag('div', { class: 'alert-text' }); - const p = createTag('p', {}, 'Alert Text'); - alertText.append(p); - alertIcon.innerHTML = alertImg; - alertIcon.append(alertText); - const alertClose = createTag('a', { class: 'alert-close', href: '#' }); - const alertCloseText = createTag('span', { class: 'alert-close-text' }, 'Close error toast'); - alertClose.innerHTML = closeImg; - alertClose.append(alertCloseText); - alertContent.append(alertIcon, alertClose); - errdom.append(alertContent); - errholder.append(errdom); - alertClose.addEventListener('click', (e) => { - e.preventDefault(); - e.target.closest('.alert-holder').style.display = 'none'; - }); - const { decorateDefaultLinkAnalytics } = await import(`${miloLibs}/martech/attributes.js`); - decorateDefaultLinkAnalytics(errholder); - return errholder; -} - -export async function showErrorToast(targetEl, unityEl, className) { - const alertHolder = targetEl.querySelector('.alert-holder'); - if (!alertHolder) { - const errorToast = await createErrorToast(); - targetEl.append(errorToast); - } - const msg = unityEl.querySelector(className)?.nextSibling.textContent; - document.querySelector('.unity-enabled .interactive-area .alert-holder .alert-toast .alert-text p').innerText = msg; - document.querySelector('.unity-enabled .interactive-area .alert-holder').style.display = 'flex'; -} - -export async function retryRequestUntilProductRedirect(cfg, requestFunction, delay = 1000) { - while (cfg.continueRetrying) { - try { - const scanResponse = await requestFunction(); - if (scanResponse.status === 429 || (scanResponse.status >= 500 && scanResponse.status < 600)) { - await new Promise((res) => setTimeout(res, delay)); - } else { - cfg.scanResponseAfterRetries = scanResponse; - return scanResponse; - } - } catch (e) { - await new Promise((res) => setTimeout(res, delay)); - } - } - return cfg.scanResponseAfterRetries; -} - -export function createIntersectionObserver({ el, callback, cfg, options = {} }) { - const io = new IntersectionObserver((entries) => { - entries.forEach((entry) => { - if (!entry.isIntersecting) { - callback(cfg); - } - }); - }, options); - io.observe(el); - return io; -} - export function delay(durationMs = 1000) { return new Promise((resolve) => { setTimeout(() => { @@ -228,7 +110,6 @@ export function updateQueryParameter(url, paramName='format', oldValue='webply', if (params.get(paramName) === oldValue) { params.set(paramName, newValue); } - return urlObj.toString(); } catch (error) { return null;