(function () { const APP_URL = "https://static-recommendations.fastsimon.com"; const PREV_APP_URL = "https://fastsimon-upsell-and-cross-sell.akamaized.net"; const WIDGET_CLASS = "fast-simon-upsell" const APP_VERSION = "1.0.272"; const CUSTOM_VERSION_LS_KEY = "no-code-recommendations-custom-endpoint"; var PORTAL_STYLES_TO_PUSH = `[{"src":"https://static-recommendations.fastsimon.com/no-code-recommendations/assets/colors.v1.0.272.css","rel":"stylesheet"}]`; const VARIATION_LS = 'fast-variation'; const DEBUG_VARIATION_LS = 'fast-debug-variation'; window["_debugNoCodeRecommendationVersion"] = (version) => { if (version) { localStorage.setItem(CUSTOM_VERSION_LS_KEY, version) } else { localStorage.removeItem(CUSTOM_VERSION_LS_KEY); } } const getSRC = () => { return localStorage.getItem(CUSTOM_VERSION_LS_KEY) || APP_URL; } const getBundleVersion = () => { if (document.querySelector(`script[src*="fs-recommendations-init.js"][src*="format=iife"]`) || document.querySelector(`script[src*="fs-recommendations-init.min.js"][src*="format=iife"]`)) { return 'iife'; } return 'umd'; } var endpoint = getSRC(); /* break this init script and inject the debug one*/ if (endpoint && endpoint !== APP_URL && !window["FS_NCR_INIT_CHANGED"]) { const thisScript = document.currentScript; if(thisScript.src && thisScript.src.includes(`${APP_URL}/no-code-recommendations/fs-recommendations-init.js`)) { let newInitScript = document.createElement('script'); newInitScript.async = true; newInitScript.type = "text/javascript"; newInitScript.src = thisScript.src.replace(APP_URL,endpoint).replace(PREV_APP_URL,endpoint); document.head.appendChild(newInitScript); window["FS_NCR_INIT_CHANGED"] = true; return; } } function appendWidget(widgetElement, target) { const {sources, dev} = widgetElement.dataset; if (!sources) { console.error("very bad :("); return; } FastRecommendationWidget.createUpsellWidget({ target, dev: !!dev }); } function appendLiveWidget(widgetElement, target, widgetID, isNewWidgetRequest, widgetsIds, newWidgetsIds) { const {settings} = widgetElement.dataset let setup = window[settings]; if(!setup) { console.log(`%c❌ Fast Simon Upsell & Cross Sell Error | WidgetID or Widget Setup Is Not Exist`, 'font-weight: bold; font-size: 12px; color: red'); return; } if (!setup.settings.recommendationGeneral.sources) { console.error("very bad :("); return; } //if the sources has been inserted as a comma splitted string if(setup.settings.recommendationGeneral.sources && typeof setup.settings.recommendationGeneral.sources === "string") { let sourcesArray = setup.settings.recommendationGeneral.sources.split(','); for(let i=0; i { const appendCallbacks = []; if(!(widgets?.length)) { return []; } widgets.forEach(element => { let target = element; if ((!window.__fast_options || !window.__fast_options?.disable_shadow_root) && !element.shadowRoot) { element.attachShadow({mode: "open", delegatesFocus: true}); target = element.shadowRoot; } if (!element.getAttribute('loaded')) { element.setAttribute('loaded', 'true'); const widgetID = element.className.split(`${widgetPrefix}-`)[1]; target.appendChild(createStyle(`${getSRC()}/no-code-recommendations/style.css`)); JSON.parse(PORTAL_STYLES_TO_PUSH).forEach(item => { target.appendChild(createLink(item.src, item.rel)); }); const variationId=getUserVariation(); let abWidgetId=undefined; const {settings} = element.dataset let setup = window[settings]; if(variationId && variationId!="fs_no_variation" && setup) { const variationWidgetConfig=setup?.variationWidgetConfig; if(variationWidgetConfig) { abWidgetId=variationWidgetConfig[widgetID]; } if(abWidgetId && abWidgetId.toString()!="0") { console.log( `%cActive AB Testing on Upsell & Cross-sell Widgets\nwidgetID: ${widgetID} ---> abVariationWidgetId: ${abWidgetId}\nvariationWidgetConfig: ${JSON.stringify(variationWidgetConfig, null, 2)}`, 'font-weight: bold; font-size: 12px; color: darkgreen' ); } else if(abWidgetId && abWidgetId.toString()=="0") { console.log( `%cActive AB Testing on Upsell & Cross-sell Widgets\nwidgetID: ${widgetID} ---> abVariationWidgetId: Hidden\nvariationWidgetConfig: ${JSON.stringify(variationWidgetConfig, null, 2)}`, 'font-weight: bold; font-size: 12px; color: darkgreen' ); return; } } // if variant customer && widgetId mapped -> the widgetId will be the mapped one, // else regular widgetId const abWidgetIdOrRegular=(abWidgetId && variationId && variationId!="fs_no_variation")?abWidgetId:widgetID; //change widget ID if needed in the element class element.className=element.className.replace(widgetID,abWidgetIdOrRegular); const div = document.createElement("div"); div.className = `fast-upsell-crossell-widget-${abWidgetIdOrRegular}`;//change widget ID if needed in the element class div.id = element.className.replace(widgetID,abWidgetIdOrRegular);//change widget ID if needed in the element Id div.tabIndex = 0; target.appendChild(div); appendCallbacks.push(() => { appendLiveWidget(element, div, abWidgetIdOrRegular, widgetPrefix.includes('new-upsell'), widgetsIds, newWidgetsIds.filter((item) => item==abWidgetIdOrRegular)?[abWidgetIdOrRegular]:newWidgetsIds); }); } }); return appendCallbacks; }; function extractedWidgetIds(nodeList, prefixClass) { return Array.from(nodeList) .map(element => element.className.split(prefixClass)[1]) .filter(Boolean); } function onScriptLoaded() { const widgets = document.querySelectorAll("div[class*='fast-simon-upsell-']"); const newWidgets = document.querySelectorAll("div[class*='fast-simon-new-upsell-']"); let appendCallbacks = []; FastRecommendationWidget.setCredentials(); const widgetsIds = extractedWidgetIds(widgets, "fast-simon-upsell-") const newWidgetsIds = extractedWidgetIds(newWidgets, "fast-simon-new-upsell-") appendCallbacks = appendCallbacks.concat(renderWidgets(widgets, 'fast-simon-upsell', widgetsIds, newWidgetsIds)); appendCallbacks = appendCallbacks.concat(renderWidgets(newWidgets, 'fast-simon-new-upsell', widgetsIds, newWidgetsIds)); if (!widgets?.length && !newWidgets?.length) { console.log(`%c❌ Fast Simon Upsell & Cross Sell Error | No Widgets Class Name Found`, 'font-weight: bold; font-size: 12px; color: red'); return; } appendCallbacks.forEach(append => append()); } function onScriptPreviewLoaded() { const widgets = [...document.querySelectorAll(`.${WIDGET_CLASS}`)]; if (widgets.length > 0) { FastRecommendationWidget.setCredentials(); widgets.forEach(element => { if(!element.shadowRoot) { element.appendChild(createStyle(`${getSRC()}/no-code-recommendations/style.css`)); JSON.parse(PORTAL_STYLES_TO_PUSH).forEach(item => { const styleElement = createLink(item.src, item.rel); element.appendChild(styleElement); }); const div = document.createElement("div"); div.className = "fast-upsell-crossell-widget"; div.id = "fast-simon-upsell-widget"; element.appendChild(div); appendWidget(element, div, true); } }); } } function appendScript(src) { const script = document.createElement("script"); script.src = `${src}?v=${APP_VERSION}`; script.async = true; if(typeof fastSimonRecommendationsIframe !== "undefined" && fastSimonRecommendationsIframe){ script.onload = onScriptPreviewLoaded; } else { script.onload = onScriptLoaded; } if(!!((window)?.requirejs)) { appendScriptWithRequirejs(script.src, script.onload); return; } document.head.appendChild(script); } function appendScriptWithRequirejs(src, onLoad) { let moduleName = "FastRecommendationWidget"; window.requirejs.config({ paths: { [moduleName]: src } }); window.requirejs(['jquery', moduleName], function ($, module) { if (module) { window[moduleName] = module; onLoad?.(); } else { $.getScript(src).done(() => { onLoad?.(); }); } }); } function injectWhenInViewport() { const widgetPlaceholders = [...document.querySelectorAll("div[class*='fast-simon-new-upsell-']"), ...document.querySelectorAll(`.${WIDGET_CLASS}`), ...document.querySelectorAll("div[class*='fast-simon-upsell-']")]; const observerCallback = (entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { appendScript(`${getSRC()}/no-code-recommendations/fast-simon-recommendation.${getBundleVersion()}.js`); widgetPlaceholders.forEach(item => observer.unobserve(item)); } }); }; let options = { root: null, rootMargin: '50% 0% 0% 0%', threshold: 0 } const observer = new IntersectionObserver(observerCallback, options); widgetPlaceholders.forEach(item => { item.style.minHeight = '300px'; observer.observe(item); }); } function shouldImmediatelyInject() { return !!(window.fs_upsell_disable_render_delay || (typeof fastSimonRecommendationsIframe !== "undefined" && fastSimonRecommendationsIframe)); } function preloadScript(src) { const link = document.createElement('link'); link.rel = 'preload'; link.as = 'script'; link.href = `${src}?v=${APP_VERSION}`; document.head.appendChild(link); } function runUpsell() { if(shouldImmediatelyInject()) { appendScript(`${getSRC()}/no-code-recommendations/fast-simon-recommendation.${getBundleVersion()}.js`); } else { preloadScript(`${getSRC()}/no-code-recommendations/fast-simon-recommendation.${getBundleVersion()}.js`); injectWhenInViewport(); } } if (document.readyState === "interactive" || document.readyState === "complete") { runUpsell(); } else { document.addEventListener("DOMContentLoaded", function () { runUpsell(); }) } function getUserVariation() { const variationId = localStorage.getItem(DEBUG_VARIATION_LS) || localStorage.getItem(VARIATION_LS) || window?.FS_VARIATION?.variation_id || undefined; if(variationId?.split(':')?.length>1) { const splittedVariation = variationId?.split(':'); return splittedVariation[splittedVariation?.length - 1]; } return variationId; } })();