From 1f13dd98636b28be1e5be0442cbccd8d86484abc Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Tue, 25 Mar 2025 13:02:35 +0530 Subject: [PATCH 01/93] ondemand POC --- events/blocks/event-agenda/event-agenda.css | 5 +++++ events/blocks/event-agenda/event-agenda.js | 12 +++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/events/blocks/event-agenda/event-agenda.css b/events/blocks/event-agenda/event-agenda.css index 4b0a186e..4c0481d1 100644 --- a/events/blocks/event-agenda/event-agenda.css +++ b/events/blocks/event-agenda/event-agenda.css @@ -140,6 +140,11 @@ flex: 100%; } +.event-agenda .fullwidth { + width: 100%; + height: 700px; +} + @media (min-width: 900px) { .event-agenda { padding: 40px 20px 32px; diff --git a/events/blocks/event-agenda/event-agenda.js b/events/blocks/event-agenda/event-agenda.js index 2abc60d3..cdfe1adc 100644 --- a/events/blocks/event-agenda/event-agenda.js +++ b/events/blocks/event-agenda/event-agenda.js @@ -17,12 +17,21 @@ export function convertToLocaleTimeFormat(time, locale) { return formatter.format(date); } +const agenda = [ + { + description: 'test2', + title: 'test1', + startTime: '08:00:00', + }, +]; + export default async function init(el) { if (getMetadata('show-agenda-post-event') !== 'true' && document.body.classList.contains('timing-post-event')) { el.remove(); return; } + createTag('iframe', { src: 'https://livekitqe.dev.adobeconnect.com/pmclu4ly06mr/?login=gbajaj@adobe.com&password=1234', frameborder: '0', allowfullscreen: 'true', class: 'fullwidth' }, '', { parent: el }); const container = createTag('div', { class: 'agenda-container' }, '', { parent: el }); const agendaItemsCol = createTag('div', { class: 'agenda-items' }, '', { parent: container }); @@ -43,7 +52,8 @@ export default async function init(el) { let agendaArray; try { - agendaArray = JSON.parse(agendaMeta); + // agendaArray = JSON.parse(agendaMeta); + agendaArray = agenda; } catch (error) { window.lana?.log('Failed to parse agenda metadata:', error); el.remove(); From 288afb001b29d49340b70f2d6134cca90e3c8bb6 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Tue, 25 Mar 2025 14:17:54 +0530 Subject: [PATCH 02/93] using participant view --- events/blocks/event-agenda/event-agenda.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/events/blocks/event-agenda/event-agenda.js b/events/blocks/event-agenda/event-agenda.js index cdfe1adc..73b83cea 100644 --- a/events/blocks/event-agenda/event-agenda.js +++ b/events/blocks/event-agenda/event-agenda.js @@ -31,7 +31,7 @@ export default async function init(el) { return; } - createTag('iframe', { src: 'https://livekitqe.dev.adobeconnect.com/pmclu4ly06mr/?login=gbajaj@adobe.com&password=1234', frameborder: '0', allowfullscreen: 'true', class: 'fullwidth' }, '', { parent: el }); + createTag('iframe', { src: 'https://livekitqe.dev.adobeconnect.com/event-demo?guestname=Participant', frameborder: '0', allowfullscreen: 'true', class: 'fullwidth' }, '', { parent: el }); const container = createTag('div', { class: 'agenda-container' }, '', { parent: el }); const agendaItemsCol = createTag('div', { class: 'agenda-items' }, '', { parent: container }); From b0230756cfe08252b71f4bf01dc17b159ba91cfd Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Wed, 26 Mar 2025 11:50:40 +0530 Subject: [PATCH 03/93] css changes --- events/blocks/event-agenda/event-agenda.css | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/events/blocks/event-agenda/event-agenda.css b/events/blocks/event-agenda/event-agenda.css index 4c0481d1..138db47f 100644 --- a/events/blocks/event-agenda/event-agenda.css +++ b/events/blocks/event-agenda/event-agenda.css @@ -1,8 +1,7 @@ .event-agenda { - max-width: 1750px; margin: auto; box-sizing: content-box; - padding: 32px 20px 0; + padding: 32px 0px 0; } .event-agenda h2 { @@ -142,12 +141,12 @@ .event-agenda .fullwidth { width: 100%; - height: 700px; + height: 900px; } @media (min-width: 900px) { .event-agenda { - padding: 40px 20px 32px; + padding: 40px 0px 32px; } .event-agenda.blade h2 { From aa0a9973181f16d5928e854ce0300250223aa87e Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Thu, 27 Mar 2025 20:58:20 +0530 Subject: [PATCH 04/93] removing padding from agenda --- events/blocks/event-agenda/event-agenda.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/events/blocks/event-agenda/event-agenda.css b/events/blocks/event-agenda/event-agenda.css index 138db47f..ed836e33 100644 --- a/events/blocks/event-agenda/event-agenda.css +++ b/events/blocks/event-agenda/event-agenda.css @@ -1,7 +1,7 @@ .event-agenda { margin: auto; box-sizing: content-box; - padding: 32px 0px 0; + padding: 0px; } .event-agenda h2 { @@ -146,7 +146,7 @@ @media (min-width: 900px) { .event-agenda { - padding: 40px 0px 32px; + padding: 0px; } .event-agenda.blade h2 { From f5a3aaf0716b1aa88cabe11a437b47b5ff77e715 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Thu, 27 Mar 2025 21:30:36 +0530 Subject: [PATCH 05/93] Agenda updates. --- events/blocks/event-agenda/event-agenda.js | 23 ++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/events/blocks/event-agenda/event-agenda.js b/events/blocks/event-agenda/event-agenda.js index 73b83cea..21da4c65 100644 --- a/events/blocks/event-agenda/event-agenda.js +++ b/events/blocks/event-agenda/event-agenda.js @@ -17,13 +17,13 @@ export function convertToLocaleTimeFormat(time, locale) { return formatter.format(date); } -const agenda = [ - { - description: 'test2', - title: 'test1', - startTime: '08:00:00', - }, -]; +// const agenda = [ +// { +// description: 'test2', +// title: 'test1', +// startTime: '08:00:00', +// }, +// ]; export default async function init(el) { if (getMetadata('show-agenda-post-event') !== 'true' && document.body.classList.contains('timing-post-event')) { @@ -52,8 +52,8 @@ export default async function init(el) { let agendaArray; try { - // agendaArray = JSON.parse(agendaMeta); - agendaArray = agenda; + agendaArray = JSON.parse(agendaMeta); + // agendaArray = agenda; } catch (error) { window.lana?.log('Failed to parse agenda metadata:', error); el.remove(); @@ -61,7 +61,10 @@ export default async function init(el) { } if (agendaArray.length <= 0) { - el.remove(); + const h2 = el.querySelector('h2'); + h2.remove(); + agendaItemsCol.remove(); + // el.remove(); return; } From 1401a58758c89f2f9151769476193264cafd7b08 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Fri, 28 Mar 2025 21:30:38 +0530 Subject: [PATCH 06/93] Adding adobe connect block --- events/blocks/adobe-connect/adobe-connect.css | 4 ++++ events/blocks/adobe-connect/adobe-connect.js | 10 ++++++++++ events/blocks/event-agenda/event-agenda.js | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 events/blocks/adobe-connect/adobe-connect.css create mode 100644 events/blocks/adobe-connect/adobe-connect.js diff --git a/events/blocks/adobe-connect/adobe-connect.css b/events/blocks/adobe-connect/adobe-connect.css new file mode 100644 index 00000000..3f46c1dc --- /dev/null +++ b/events/blocks/adobe-connect/adobe-connect.css @@ -0,0 +1,4 @@ +.adobe-connect .fullwidth { + width: 100%; + height: 900px; + } \ No newline at end of file diff --git a/events/blocks/adobe-connect/adobe-connect.js b/events/blocks/adobe-connect/adobe-connect.js new file mode 100644 index 00000000..34da2b06 --- /dev/null +++ b/events/blocks/adobe-connect/adobe-connect.js @@ -0,0 +1,10 @@ +import { LIBS } from '../../scripts/utils.js'; + +const { createTag } = await import(`${LIBS}/utils/utils.js`); + +export default async function init(el) { + const h2 = el.querySelector('h2'); + const url = h2?.textContent; + h2.remove(); + createTag('iframe', { src: url, frameborder: '0', allowfullscreen: 'true', class: 'fullwidth' }, '', { parent: el }); +} diff --git a/events/blocks/event-agenda/event-agenda.js b/events/blocks/event-agenda/event-agenda.js index 21da4c65..960771f7 100644 --- a/events/blocks/event-agenda/event-agenda.js +++ b/events/blocks/event-agenda/event-agenda.js @@ -31,7 +31,7 @@ export default async function init(el) { return; } - createTag('iframe', { src: 'https://livekitqe.dev.adobeconnect.com/event-demo?guestname=Participant', frameborder: '0', allowfullscreen: 'true', class: 'fullwidth' }, '', { parent: el }); + // createTag('iframe', { src: 'https://livekitqe.dev.adobeconnect.com/event-demo?guestname=Participant', frameborder: '0', allowfullscreen: 'true', class: 'fullwidth' }, '', { parent: el }); const container = createTag('div', { class: 'agenda-container' }, '', { parent: el }); const agendaItemsCol = createTag('div', { class: 'agenda-items' }, '', { parent: container }); From ef17959f0b719f9fe1fef3a3862f836437a3e721 Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Tue, 13 May 2025 21:19:56 -0400 Subject: [PATCH 07/93] WIP. To test --- events/blocks/chrono-box/chrono-box.js | 9 + events/features/timing-framework/testing.js | 11 + events/features/timing-framework/worker.js | 272 +++++++++++--------- 3 files changed, 164 insertions(+), 128 deletions(-) create mode 100644 events/features/timing-framework/testing.js diff --git a/events/blocks/chrono-box/chrono-box.js b/events/blocks/chrono-box/chrono-box.js index cebf0f8e..b4e77691 100644 --- a/events/blocks/chrono-box/chrono-box.js +++ b/events/blocks/chrono-box/chrono-box.js @@ -1,3 +1,4 @@ +import { getToggleTimeFromParams, getScheduleItemFromParams } from '../../features/timing-framework/testing.js'; import { readBlockConfig, LIBS, getMetadata } from '../../scripts/utils.js'; function buildScheduleDoubleLinkedList(entries) { @@ -59,6 +60,10 @@ function setScheduleToScheduleWorker(schedule) { message: 'schedule', schedule: scheduleLinkedList, conditions, + testing: { + toggleTime: getToggleTimeFromParams(), + scheduleItemId: getScheduleItemFromParams(), + }, }); return worker; @@ -101,6 +106,10 @@ export default async function init(el) { worker.postMessage({ schedule, conditions, + testing: { + toggleTime: getToggleTimeFromParams(), + scheduleItemId: getScheduleItemFromParams(), + }, }); }); diff --git a/events/features/timing-framework/testing.js b/events/features/timing-framework/testing.js new file mode 100644 index 00000000..daa28235 --- /dev/null +++ b/events/features/timing-framework/testing.js @@ -0,0 +1,11 @@ +export function getToggleTimeFromParams() { + const params = new URLSearchParams(document.location.search); + const testTiming = params.get('timing'); + return testTiming; +} + +export function getScheduleItemFromParams() { + const params = new URLSearchParams(document.location.search); + const scheduleItemId = params.get('scheduleItemId'); + return scheduleItemId; +} diff --git a/events/features/timing-framework/worker.js b/events/features/timing-framework/worker.js index b93032a1..db04e823 100644 --- a/events/features/timing-framework/worker.js +++ b/events/features/timing-framework/worker.js @@ -1,157 +1,173 @@ -let conditionStore = null; -let currentScheduleItem = null; -let nextScheduleItem = null; -let timerId = null; - -/** - * @returns {number} - * @description Returns the current time from the API - */ -async function getCurrentTimeFromAPI() { - try { - const response = await fetch('https://worldtimeapi.org/api/ip'); - const data = await response.json(); - return new Date(data.datetime).getTime(); - } catch (error) { - console.error('Error fetching time from API:', error); - return null; +class TimingWorker { + constructor() { + this.conditionStore = null; + this.currentScheduleItem = null; + this.nextScheduleItem = null; + this.timerId = null; + this.setupMessageHandler(); } -} -/** - * @param {Object} scheduleRoot - * @param {Object} cs: conditionStore - * @returns {Object} - * @description Returns the first schedule item that should be shown - */ -function getStartScheduleItem(scheduleRoot, cs) { - const currentTime = new Date().getTime(); - let pointer = scheduleRoot; - let start = null; - - // Scan phase 1: Fast forward through toggleTime-only - while (pointer) { - const { toggleTime: t } = pointer; - const toggleTimePassed = typeof t !== 'number' || currentTime > t; - - if (!toggleTimePassed) break; - - start = pointer; - pointer = pointer.next; + /** + * @returns {number} + * @description Returns the current time from the API + */ + static async getCurrentTimeFromAPI() { + try { + const response = await fetch('https://worldtimeapi.org/api/ip'); + const data = await response.json(); + return new Date(data.datetime).getTime(); + } catch (error) { + console.error('Error fetching time from API:', error); + return null; + } } - // Scan Phase 2: Scan from last toggleTime match forward with condition checks - pointer = start || scheduleRoot; - - while (pointer) { - const { toggleTime: t, conditions: c } = pointer; - const toggleTimePassed = !t || currentTime > t; - const conditionsMet = !c || c.every(({ key: k, expectedValue: v }) => { - const val = cs?.[k]; - const isAny = v.trim().toLowerCase() === 'any' && !!val; - return isAny || val === v; - }); + /** + * @param {Object} scheduleRoot + * @param {Object} cs: conditionStore + * @returns {Object} + * @description Returns the first schedule item that should be shown + */ + static getStartScheduleItem(scheduleRoot, cs, testing = {}) { + const currentTime = testing.toggleTime || new Date().getTime(); + let pointer = scheduleRoot; + let start = null; + + // Scan phase 1: Fast forward through toggleTime-only + while (pointer) { + const { toggleTime: t } = pointer; + const toggleTimePassed = typeof t !== 'number' || currentTime > t; + + if (!toggleTimePassed) break; + + start = pointer; + pointer = pointer.next; + } - if (toggleTimePassed && conditionsMet) return pointer; + // Scan Phase 2: Scan from last toggleTime match forward with condition checks + pointer = start || scheduleRoot; - pointer = pointer.next; - } + while (pointer) { + const { toggleTime: t, conditions: c } = pointer; + const toggleTimePassed = !t || currentTime > t; + const conditionsMet = !c || c.every(({ key: k, expectedValue: v }) => { + const val = cs?.[k]; + const isAny = v.trim().toLowerCase() === 'any' && !!val; + return isAny || val === v; + }); - return scheduleRoot; -} + if (toggleTimePassed && conditionsMet) return pointer; -/** - * @returns {number} - * @description Returns a random interval between 1 and 1.5 seconds - */ -function getRandomInterval() { - const min = 500; - const max = 1500; - return Math.floor(Math.random() * (max - min + 1)) + min; -} + pointer = pointer.next; + } -/** - * @param {Object} scheduleItem - * @returns {boolean} - * @description Returns true if the next schedule item is triggered - */ -function isNextScheduleTriggered(scheduleItem) { - if (!scheduleItem) return false; - const { conditions: c, toggleTime: t } = scheduleItem; - const currentTime = new Date().getTime(); - - const toggleTimePassed = !t || currentTime > t; - - const conditionsMet = !c || c.every(({ key: k, expectedValue: v }) => { - const conditionValue = conditionStore?.[k]; - const isAnyVal = v.trim().toLowerCase() === 'any' && !!conditionValue; - return isAnyVal || conditionValue === v; - }); - - return toggleTimePassed && conditionsMet; -} + return scheduleRoot; + } -/** - * @param {number} currentTime - * @returns {boolean} - * @description Returns true if the current time is valid - */ -// eslint-disable-next-line no-unused-vars -async function validateTime(currentTime) { - const apiCurrentTime = await getCurrentTimeFromAPI(); - const diff = apiCurrentTime - currentTime; - - if (diff > 10000) { - window.alert('Sorry. Your local time is off by more than 10 seconds. Please check your system clock.'); - return false; + /** + * @returns {number} + * @description Returns a random interval between 1 and 1.5 seconds + */ + static getRandomInterval() { + const min = 500; + const max = 1500; + return Math.floor(Math.random() * (max - min + 1)) + min; } - return true; -} + /** + * @param {Object} scheduleItem + * @returns {boolean} + * @description Returns true if the next schedule item is triggered + */ + isNextScheduleTriggered(scheduleItem) { + if (!scheduleItem) return false; + const { conditions: c, toggleTime: t } = scheduleItem; + const currentTime = new Date().getTime(); -/** - * @param {Object} event - * @description Handles messages from the main thread - */ -onmessage = async (event) => { - const { schedule, conditions } = event.data; + const toggleTimePassed = !t || currentTime > t; - if (timerId) { - clearTimeout(timerId); - timerId = null; - } + const conditionsMet = !c || c.every(({ key: k, expectedValue: v }) => { + const conditionValue = this.conditionStore?.[k]; + const isAnyVal = v.trim().toLowerCase() === 'any' && !!conditionValue; + return isAnyVal || conditionValue === v; + }); - if (conditions) { - conditionStore = { ...conditionStore, ...conditions }; + return toggleTimePassed && conditionsMet; } - if (schedule) { - nextScheduleItem = getStartScheduleItem(schedule, conditionStore); - currentScheduleItem = nextScheduleItem?.prev || schedule; - } + /** + * @param {number} currentTime + * @returns {boolean} + * @description Returns true if the current time is valid + */ + static async validateTime(currentTime) { + const apiCurrentTime = await TimingWorker.getCurrentTimeFromAPI(); + const diff = apiCurrentTime - currentTime; + + if (diff > 10000) { + window.alert('Sorry. Your local time is off by more than 10 seconds. Please check your system clock.'); + return false; + } - if (!nextScheduleItem) return; + return true; + } - const runTimer = async () => { - const triggered = isNextScheduleTriggered(nextScheduleItem); + async runTimer() { + const triggered = this.isNextScheduleTriggered(this.nextScheduleItem); - const { pathToFragment: currentPath } = currentScheduleItem; - const { pathToFragment: nextPath, prev: nextPrev } = nextScheduleItem; + const { pathToFragment: currentPath } = this.currentScheduleItem; + const { pathToFragment: nextPath, prev: nextPrev } = this.nextScheduleItem; if (triggered && (nextPath !== currentPath || nextPrev === null)) { - // const timeValid = await validateTime(currentTime); + // const timeValid = await this.validateTime(currentTime); // if (!timeValid) return; - postMessage(nextScheduleItem); + postMessage(this.nextScheduleItem); + + this.currentScheduleItem = { ...this.nextScheduleItem }; + this.nextScheduleItem = this.nextScheduleItem.next; + } + + if (!this.nextScheduleItem) return; + + this.timerId = setTimeout(() => this.runTimer(), TimingWorker.getRandomInterval()); + } + + handleMessage(event) { + const { schedule, conditions, testing } = event.data; + + if (this.timerId) { + clearTimeout(this.timerId); + this.timerId = null; + } + + if (conditions) { + this.conditionStore = { ...this.conditionStore, ...conditions }; + } + + if (schedule) { + this.nextScheduleItem = TimingWorker.getStartScheduleItem( + schedule, + this.conditionStore, + testing, + ); + this.currentScheduleItem = this.nextScheduleItem?.prev || schedule; + } - currentScheduleItem = { ...nextScheduleItem }; - nextScheduleItem = nextScheduleItem.next; + if (testing.scheduleItemId) { + this.nextScheduleItem = schedule.find((item) => item.id === testing.scheduleItemId); + this.currentScheduleItem = this.nextScheduleItem?.prev || schedule; } - if (!nextScheduleItem) return; + if (!this.nextScheduleItem) return; - timerId = setTimeout(runTimer, getRandomInterval()); - }; + this.runTimer(); + } + + setupMessageHandler() { + onmessage = (event) => this.handleMessage(event); + } +} - runTimer(); -}; +// Initialize the worker +(() => new TimingWorker())(); From 7907c4e45b579520411ec4503ebf33299f5c5d5b Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Wed, 14 May 2025 11:05:53 +0530 Subject: [PATCH 08/93] fix changes --- events/blocks/adobe-connect/adobe-connect.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/events/blocks/adobe-connect/adobe-connect.js b/events/blocks/adobe-connect/adobe-connect.js index 34da2b06..02fc5406 100644 --- a/events/blocks/adobe-connect/adobe-connect.js +++ b/events/blocks/adobe-connect/adobe-connect.js @@ -4,7 +4,8 @@ const { createTag } = await import(`${LIBS}/utils/utils.js`); export default async function init(el) { const h2 = el.querySelector('h2'); - const url = h2?.textContent; + let url = h2?.textContent; + url += '&mkto_trk=abcs'; h2.remove(); createTag('iframe', { src: url, frameborder: '0', allowfullscreen: 'true', class: 'fullwidth' }, '', { parent: el }); } From c06004dff48cfd3259fa1ac54185d252cc024fc2 Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Wed, 14 May 2025 12:27:17 -0400 Subject: [PATCH 09/93] remove event type specific template callbacks --- events/scripts/content-update.js | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/events/scripts/content-update.js b/events/scripts/content-update.js index 1fa204d8..595a6494 100644 --- a/events/scripts/content-update.js +++ b/events/scripts/content-update.js @@ -284,29 +284,6 @@ function autoUpdateLinks(scope, miloLibs) { }, }; - const templateLoadCallbacks = { - online: (a, templateId) => { - a.href = templateId; - }, - inperson: (a, templateId) => { - const params = new URLSearchParams(document.location.search); - const testTiming = params.get('timing'); - let timeSuffix = ''; - - if (testTiming) { - timeSuffix = +testTiming > +getMetadata('local-end-time-millis') ? '-post' : '-pre'; - } else { - const currentDate = new Date(); - const currentTimestamp = currentDate.getTime(); - timeSuffix = currentTimestamp > +getMetadata('local-end-time-millis') ? '-post' : '-pre'; - } - - a.href = `${templateId}${timeSuffix}`; - const timingClass = `timing${timeSuffix}-event`; - document.body.classList.add(timingClass); - }, - }; - scope.querySelectorAll('a[href*="#"]').forEach(async (a) => { try { const url = new URL(a.href); @@ -342,12 +319,7 @@ function autoUpdateLinks(scope, miloLibs) { } if (templateId) { - const eventType = getMetadata('event-type'); - if (eventType && templateLoadCallbacks[eventType.toLowerCase()]) { - templateLoadCallbacks[eventType.toLowerCase()](a, templateId); - } else { - window.lana?.log(`Error: Failed to find template ID for event ${getMetadata('event-id')} due to missing event type`); - } + a.href = templateId; } else { window.lana?.log(`Error: Failed to find template ID for event ${getMetadata('event-id')}`); } From 90e810f52bc8e6a9acf912bc677478a93ba07ff7 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Thu, 15 May 2025 22:29:44 +0530 Subject: [PATCH 10/93] url based query param for connect. --- events/blocks/adobe-connect/adobe-connect.js | 26 +++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/events/blocks/adobe-connect/adobe-connect.js b/events/blocks/adobe-connect/adobe-connect.js index 02fc5406..186aa6ae 100644 --- a/events/blocks/adobe-connect/adobe-connect.js +++ b/events/blocks/adobe-connect/adobe-connect.js @@ -2,10 +2,34 @@ import { LIBS } from '../../scripts/utils.js'; const { createTag } = await import(`${LIBS}/utils/utils.js`); +function addParams(searchParams, params, key, value) { + if (params.has(key)) { + searchParams[key] = params.get(key); + } else { + searchParams[key] = value; + } +} + +function addSearchParams(url, searchParams) { + const urlObj = new URL(url); + for (const [key, value] of Object.entries(searchParams)) { + urlObj.searchParams.append(key, value); + } + return urlObj.toString(); +} + export default async function init(el) { const h2 = el.querySelector('h2'); let url = h2?.textContent; - url += '&mkto_trk=abcs'; + + const params = new URL(window.location.href).searchParams; + const searchParams = {}; + addParams(searchParams, params, 'mkto_trk', 'marketo_tracker'); + addParams(searchParams, params, 'mkt_tok', 'marketo_token'); + addParams(searchParams, params, 'ecid', 'experience_cloud_id'); + addParams(searchParams, params, 'mkto_event_id', 'marketo_event_id'); + + url = addSearchParams(url, searchParams); h2.remove(); createTag('iframe', { src: url, frameborder: '0', allowfullscreen: 'true', class: 'fullwidth' }, '', { parent: el }); } From 60d6c6305f3ff5ca94e3d22a6fa2053c091da7b9 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Mon, 19 May 2025 14:07:46 +0530 Subject: [PATCH 11/93] Minor enhancements to support marketo form and adobe connect behind a button --- events/blocks/adobe-connect/adobe-connect.css | 25 +++++++++++++++++++ events/blocks/adobe-connect/adobe-connect.js | 24 +++++++++++------- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/events/blocks/adobe-connect/adobe-connect.css b/events/blocks/adobe-connect/adobe-connect.css index 3f46c1dc..3364010c 100644 --- a/events/blocks/adobe-connect/adobe-connect.css +++ b/events/blocks/adobe-connect/adobe-connect.css @@ -1,4 +1,29 @@ +.adobe-connect { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 100%; + padding: 0 16px; +} .adobe-connect .fullwidth { width: 100%; height: 900px; + } + + .adobe-connect button { + font-size: var(--type-body-s-size); + background-color: var(--link-color); + min-width: 114px; + height: 40px; + line-height: 20px; + padding: 9px 16px; + border: 0; + border-radius: 24px; + color: #fff; + font-weight: 700; + box-shadow: none; + margin: 0 auto; + cursor: pointer; + transition: background-color 0.13s, color 0.13s; } \ No newline at end of file diff --git a/events/blocks/adobe-connect/adobe-connect.js b/events/blocks/adobe-connect/adobe-connect.js index 186aa6ae..18df4f27 100644 --- a/events/blocks/adobe-connect/adobe-connect.js +++ b/events/blocks/adobe-connect/adobe-connect.js @@ -21,15 +21,21 @@ function addSearchParams(url, searchParams) { export default async function init(el) { const h2 = el.querySelector('h2'); let url = h2?.textContent; - - const params = new URL(window.location.href).searchParams; - const searchParams = {}; - addParams(searchParams, params, 'mkto_trk', 'marketo_tracker'); - addParams(searchParams, params, 'mkt_tok', 'marketo_token'); - addParams(searchParams, params, 'ecid', 'experience_cloud_id'); - addParams(searchParams, params, 'mkto_event_id', 'marketo_event_id'); - url = addSearchParams(url, searchParams); h2.remove(); - createTag('iframe', { src: url, frameborder: '0', allowfullscreen: 'true', class: 'fullwidth' }, '', { parent: el }); + const button = createTag('button', { class: 'button' }, 'Join the event', { parent: el }); + + button.addEventListener('click', () => { + const params = new URL(window.location.href).searchParams; + const searchParams = {}; + addParams(searchParams, params, 'mkto_trk', 'marketo_tracker'); + addParams(searchParams, params, 'mkt_tok', 'marketo_token'); + addParams(searchParams, params, 'ecid', 'experience_cloud_id'); + addParams(searchParams, params, 'mkto_event_id', 'marketo_event_id'); + + url = addSearchParams(url, searchParams); + createTag('iframe', { src: url, frameborder: '0', allowfullscreen: 'true', class: 'fullwidth' }, '', { parent: el }); + button.remove(); + document.body.querySelector('#webinar-marketo-form')?.remove(); + }); } From 2e09e98b2a08fb332b5370cc6b53e273ac050c90 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Mon, 19 May 2025 16:00:04 +0530 Subject: [PATCH 12/93] Adding Script file for marketo --- head.html | 1 + rs/360-KCI-804/images/mktoTestFormConfig.js | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 rs/360-KCI-804/images/mktoTestFormConfig.js diff --git a/head.html b/head.html index 373ade09..d7930281 100644 --- a/head.html +++ b/head.html @@ -2,6 +2,7 @@ + diff --git a/rs/360-KCI-804/images/mktoTestFormConfig.js b/rs/360-KCI-804/images/mktoTestFormConfig.js new file mode 100644 index 00000000..b8611249 --- /dev/null +++ b/rs/360-KCI-804/images/mktoTestFormConfig.js @@ -0,0 +1,3 @@ +var mktoTestFormConfig = ` +#eyJmb3JtLnRlbXBsYXRlIjoicmVxdWVzdF9mb3JfaW5mb3JtYXRpb24iLCJmb3JtLnN1YnR5cGUiOiJyZXF1ZXN0X2Zvcl9pbmZvcm1hdGlvbiIsInByb2dyYW0uY2FtcGFpZ25pZHMuc2ZkYyI6IjcwMTE0MDAwMDAyWFl2SUFBVyIsInByb2dyYW0ucG9pIjoiTUFSS0VUT0VOR0FHRU1FTlRQTEFURk9STSIsImZvcm0uc3VjY2Vzcy5jb250ZW50IjoiaHR0cHM6Ly9idXNpbmVzcy5hZG9iZS5jb20vcmVzb3VyY2VzL2Vib29rcy9wcm92aW5nLXRoZS1pbXBhY3Qtb2YtbWFya2V0aW5nLW9uLXJldmVudWUvdGhhbmsteW91Lmh0bWwiLCJmb3JtLnN1Y2Nlc3MudHlwZSI6IiIsInByb2dyYW0uY29udGVudC50eXBlIjoiIiwicHJvZ3JhbS5jb250ZW50LmlkIjoiIiwiZmllbGRfdmlzaWJpbGl0eS5uYW1lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBob25lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnkiOiJyZXF1aXJlZCIsImZpZWxkX3Zpc2liaWxpdHkud2Vic2l0ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5mdW5jdGlvbmFsX2FyZWEiOiJGdW5jdGlvbmFsIEFyZWEtRFgiLCJmaWVsZF92aXNpYmlsaXR5LnN0YXRlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBvc3Rjb2RlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnlfc2l6ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5wcm9kdWN0cyI6ImhpZGRlbiIsImZpZWxkX2ZpbHRlcnMuaW5kdXN0cnkiOiJoaWRkZW4iLCJmaWVsZF9maWx0ZXJzLmpvYl9yb2xlIjoiYWxsIiwiZmllbGRfdmlzaWJpbGl0eS5jb21tZW50cyI6ImhpZGRlbiIsImZpZWxkX3Zpc2liaWxpdHkuZGVtbyI6ImhpZGRlbiIsInByb2dyYW0uY29wYXJ0bmVybmFtZXMiOiIiLCJwcm9ncmFtLmNhbXBhaWduaWRzLmV4dGVybmFsIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5yZXRvdWNoIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5vbnNpdGUiOiIiLCJwcm9ncmFtLmFkZGl0aW9uYWxfZm9ybV9pZCI6IiIsImZvcm0gaWQiOiIxNzIzIiwibWFya2V0byBtdW5ja2luIjoiMzYwLUtDSS04MDQiLCJtYXJrZXRvIGhvc3QiOiJlbmdhZ2UuYWRvYmUuY29tIiwiZm9ybSB0eXBlIjoibWFya2V0b19mb3JtIn0=) +`; \ No newline at end of file From 15b9fa587f18b9e3f3a28fbbed43822408129606 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Thu, 22 May 2025 18:34:12 +0530 Subject: [PATCH 13/93] support for join url --- events/blocks/adobe-connect/adobe-connect.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/events/blocks/adobe-connect/adobe-connect.js b/events/blocks/adobe-connect/adobe-connect.js index 18df4f27..277f19e0 100644 --- a/events/blocks/adobe-connect/adobe-connect.js +++ b/events/blocks/adobe-connect/adobe-connect.js @@ -33,6 +33,9 @@ export default async function init(el) { addParams(searchParams, params, 'ecid', 'experience_cloud_id'); addParams(searchParams, params, 'mkto_event_id', 'marketo_event_id'); + if (window.join_url) { + url = window.join_url; + } url = addSearchParams(url, searchParams); createTag('iframe', { src: url, frameborder: '0', allowfullscreen: 'true', class: 'fullwidth' }, '', { parent: el }); button.remove(); From ea9b7fe97025c348207c893d2c96f42abaea5194 Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Thu, 22 May 2025 10:48:05 -0400 Subject: [PATCH 14/93] Lana log --- events/features/timing-framework/worker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/events/features/timing-framework/worker.js b/events/features/timing-framework/worker.js index db04e823..18a286aa 100644 --- a/events/features/timing-framework/worker.js +++ b/events/features/timing-framework/worker.js @@ -17,7 +17,7 @@ class TimingWorker { const data = await response.json(); return new Date(data.datetime).getTime(); } catch (error) { - console.error('Error fetching time from API:', error); + window.lana?.log(`Error fetching time from API: ${JSON.stringify(error)}`); return null; } } From 53ef912eb994bea86158b3e721f0cd32fca80860 Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Thu, 22 May 2025 11:06:00 -0400 Subject: [PATCH 15/93] MR refactor WIP --- events/blocks/chrono-box/chrono-box.js | 24 ++++++++++ .../timing-framework/mobile-rider-plugin.js | 42 ++++++++++++++++ events/features/timing-framework/worker.js | 48 ++++++++++++++----- 3 files changed, 103 insertions(+), 11 deletions(-) create mode 100644 events/features/timing-framework/mobile-rider-plugin.js diff --git a/events/blocks/chrono-box/chrono-box.js b/events/blocks/chrono-box/chrono-box.js index b4e77691..4269d170 100644 --- a/events/blocks/chrono-box/chrono-box.js +++ b/events/blocks/chrono-box/chrono-box.js @@ -77,6 +77,14 @@ export default async function init(el) { import(`${LIBS}/features/spectrum-web-components/dist/progress-circle.js`), ]); + // Check if MobileRider is enabled + const isMobileRiderEnabled = el.classList.contains('mobile-rider-enabled'); + + if (isMobileRiderEnabled) { + // Load MobileRider plugin + await import('../../features/timing-framework/mobile-rider-plugin.js'); + } + const blockConfig = readBlockConfig(el); const scheduleId = blockConfig?.['schedule-id']; let staticSchedule; @@ -100,6 +108,22 @@ export default async function init(el) { const worker = setScheduleToScheduleWorker(thisSchedule); + // Add periodic MR session status check + if (isMobileRiderEnabled) { + setInterval(async () => { + const sessionIds = thisSchedule + .filter((item) => item.mobileRiderSessionId) + .map((item) => item.mobileRiderSessionId); + + if (sessionIds.length > 0) { + worker.postMessage({ + type: 'update_mr_status', + sessionIds, + }); + } + }, 5000); // Check every 5 seconds + } + el.addEventListener('worker-message', (e) => { const { schedule, conditions } = e.detail.data; diff --git a/events/features/timing-framework/mobile-rider-plugin.js b/events/features/timing-framework/mobile-rider-plugin.js new file mode 100644 index 00000000..18fbc564 --- /dev/null +++ b/events/features/timing-framework/mobile-rider-plugin.js @@ -0,0 +1,42 @@ +export default class MobileRiderPlugin { + constructor() { + this.sessions = new Map(); // Store session statuses + this.baseUrl = 'https://overlay-admin-dev.mobilerider.com'; + } + + async fetchSessionStatus(sessionIds) { + try { + const response = await fetch(`${this.baseUrl}/api/media-status?ids=${sessionIds.join(',')}`); + const data = await response.json(); + + // Update session statuses + data.active.forEach((id) => this.sessions.set(id, 'active')); + data.inactive.forEach((id) => this.sessions.set(id, 'inactive')); + + return data; + } catch (error) { + window.lana?.log(`Error fetching MobileRider session status: ${JSON.stringify(error)}`); + return null; + } + } + + isSessionActive(sessionId) { + return this.sessions.get(sessionId) === 'active'; + } + + async initializeSessions(schedule) { + // Extract all MR session IDs from the schedule + const sessionIds = []; + let current = schedule; + while (current) { + if (current.mobileRiderSessionId) { + sessionIds.push(current.mobileRiderSessionId); + } + current = current.next; + } + + if (sessionIds.length > 0) { + await this.fetchSessionStatus(sessionIds); + } + } +} diff --git a/events/features/timing-framework/worker.js b/events/features/timing-framework/worker.js index 18a286aa..09f8866c 100644 --- a/events/features/timing-framework/worker.js +++ b/events/features/timing-framework/worker.js @@ -1,9 +1,12 @@ +import MobileRiderPlugin from './mobile-rider-plugin.js'; + class TimingWorker { constructor() { this.conditionStore = null; this.currentScheduleItem = null; this.nextScheduleItem = null; this.timerId = null; + this.mobileRiderPlugin = new MobileRiderPlugin(); this.setupMessageHandler(); } @@ -33,6 +36,17 @@ class TimingWorker { let pointer = scheduleRoot; let start = null; + // First, check if there's an active MR session that should take precedence + while (pointer) { + if (pointer.mobileRiderSessionId && cs[`mr_session_${pointer.mobileRiderSessionId}`] === 'active') { + return pointer; + } + pointer = pointer.next; + } + + // Reset pointer and continue with normal schedule logic + pointer = scheduleRoot; + // Scan phase 1: Fast forward through toggleTime-only while (pointer) { const { toggleTime: t } = pointer; @@ -81,6 +95,14 @@ class TimingWorker { */ isNextScheduleTriggered(scheduleItem) { if (!scheduleItem) return false; + + // Check if current item is an MR session + if (scheduleItem.mobileRiderSessionId) { + const sessionStatus = this.conditionStore?.[`mr_session_${scheduleItem.mobileRiderSessionId}`]; + // If session is active, don't trigger next item + if (sessionStatus === 'active') return false; + } + const { conditions: c, toggleTime: t } = scheduleItem; const currentTime = new Date().getTime(); @@ -133,7 +155,7 @@ class TimingWorker { this.timerId = setTimeout(() => this.runTimer(), TimingWorker.getRandomInterval()); } - handleMessage(event) { + async handleMessage(event) { const { schedule, conditions, testing } = event.data; if (this.timerId) { @@ -141,17 +163,21 @@ class TimingWorker { this.timerId = null; } - if (conditions) { - this.conditionStore = { ...this.conditionStore, ...conditions }; - } - if (schedule) { - this.nextScheduleItem = TimingWorker.getStartScheduleItem( - schedule, - this.conditionStore, - testing, - ); - this.currentScheduleItem = this.nextScheduleItem?.prev || schedule; + // Initialize MR sessions if needed + await this.mobileRiderPlugin.initializeSessions(schedule); + + // Update conditions with MR session statuses + const mrConditions = {}; + this.mobileRiderPlugin.sessions.forEach((status, id) => { + mrConditions[`mr_session_${id}`] = status; + }); + + this.conditionStore = { + ...this.conditionStore, + ...conditions, + ...mrConditions, + }; } if (testing.scheduleItemId) { From a3ad3f1721152a66b21ca13858dfb7d35f6ac9f8 Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Thu, 22 May 2025 11:19:43 -0400 Subject: [PATCH 16/93] WIP --- events/blocks/chrono-box/chrono-box.js | 50 +++++++----- .../timing-framework/mobile-rider-plugin.js | 18 +++++ events/features/timing-framework/worker.js | 79 ++++++++++++++----- 3 files changed, 108 insertions(+), 39 deletions(-) diff --git a/events/blocks/chrono-box/chrono-box.js b/events/blocks/chrono-box/chrono-box.js index 4269d170..954bf899 100644 --- a/events/blocks/chrono-box/chrono-box.js +++ b/events/blocks/chrono-box/chrono-box.js @@ -77,14 +77,6 @@ export default async function init(el) { import(`${LIBS}/features/spectrum-web-components/dist/progress-circle.js`), ]); - // Check if MobileRider is enabled - const isMobileRiderEnabled = el.classList.contains('mobile-rider-enabled'); - - if (isMobileRiderEnabled) { - // Load MobileRider plugin - await import('../../features/timing-framework/mobile-rider-plugin.js'); - } - const blockConfig = readBlockConfig(el); const scheduleId = blockConfig?.['schedule-id']; let staticSchedule; @@ -104,12 +96,19 @@ export default async function init(el) { return; } - el.innerHTML = ''; + // Check if schedule contains any MR sessions + const hasMRSessions = thisSchedule.some((item) => item.mobileRiderSessionId); + // Only add the class if MR sessions are present + if (hasMRSessions) { + el.classList.add('mobile-rider-enabled'); + } + + el.innerHTML = ''; const worker = setScheduleToScheduleWorker(thisSchedule); // Add periodic MR session status check - if (isMobileRiderEnabled) { + if (hasMRSessions) { setInterval(async () => { const sessionIds = thisSchedule .filter((item) => item.mobileRiderSessionId) @@ -125,16 +124,27 @@ export default async function init(el) { } el.addEventListener('worker-message', (e) => { - const { schedule, conditions } = e.detail.data; - - worker.postMessage({ - schedule, - conditions, - testing: { - toggleTime: getToggleTimeFromParams(), - scheduleItemId: getScheduleItemFromParams(), - }, - }); + const { type, schedule, conditions, sessionId, status } = e.detail.data; + + if (type === 'mr_session_update') { + // Handle MR session status update + worker.postMessage({ + type: 'update_mr_status', + sessionId, + status, + timestamp: Date.now(), + }); + } else { + // Handle regular schedule/condition updates + worker.postMessage({ + schedule, + conditions, + testing: { + toggleTime: getToggleTimeFromParams(), + scheduleItemId: getScheduleItemFromParams(), + }, + }); + } }); worker.onmessage = (event) => { diff --git a/events/features/timing-framework/mobile-rider-plugin.js b/events/features/timing-framework/mobile-rider-plugin.js index 18fbc564..7705c048 100644 --- a/events/features/timing-framework/mobile-rider-plugin.js +++ b/events/features/timing-framework/mobile-rider-plugin.js @@ -39,4 +39,22 @@ export default class MobileRiderPlugin { await this.fetchSessionStatus(sessionIds); } } + + static createSessionStatusEvent(sessionId, status) { + return new CustomEvent('worker-message', { + detail: { + data: { + type: 'mr_session_update', + sessionId, + status, + timestamp: Date.now(), + }, + }, + }); + } + + static dispatchSessionStatusEvent(element, sessionId, status) { + const event = this.createSessionStatusEvent(sessionId, status); + element.dispatchEvent(event); + } } diff --git a/events/features/timing-framework/worker.js b/events/features/timing-framework/worker.js index 09f8866c..b3801002 100644 --- a/events/features/timing-framework/worker.js +++ b/events/features/timing-framework/worker.js @@ -1,12 +1,10 @@ -import MobileRiderPlugin from './mobile-rider-plugin.js'; - class TimingWorker { constructor() { this.conditionStore = null; this.currentScheduleItem = null; this.nextScheduleItem = null; this.timerId = null; - this.mobileRiderPlugin = new MobileRiderPlugin(); + this.mobileRiderPlugin = null; this.setupMessageHandler(); } @@ -96,10 +94,9 @@ class TimingWorker { isNextScheduleTriggered(scheduleItem) { if (!scheduleItem) return false; - // Check if current item is an MR session - if (scheduleItem.mobileRiderSessionId) { + // Only check MR conditions if plugin is initialized + if (this.mobileRiderPlugin && scheduleItem.mobileRiderSessionId) { const sessionStatus = this.conditionStore?.[`mr_session_${scheduleItem.mobileRiderSessionId}`]; - // If session is active, don't trigger next item if (sessionStatus === 'active') return false; } @@ -156,28 +153,64 @@ class TimingWorker { } async handleMessage(event) { - const { schedule, conditions, testing } = event.data; + const { + type, schedule, conditions, sessionId, status, testing, + } = event.data; if (this.timerId) { clearTimeout(this.timerId); this.timerId = null; } - if (schedule) { - // Initialize MR sessions if needed - await this.mobileRiderPlugin.initializeSessions(schedule); - - // Update conditions with MR session statuses - const mrConditions = {}; - this.mobileRiderPlugin.sessions.forEach((status, id) => { - mrConditions[`mr_session_${id}`] = status; - }); - + if (type === 'update_mr_status') { + // Update condition store with new session status this.conditionStore = { ...this.conditionStore, - ...conditions, - ...mrConditions, + [`mr_session_${sessionId}`]: status, }; + + // If current item is the updated session and it's now inactive, + // we need to re-evaluate the schedule + if (this.currentScheduleItem?.mobileRiderSessionId === sessionId && status === 'inactive') { + // Session has ended (underrun), check if we should move to next item + if (this.nextScheduleItem) { + const shouldMoveToNext = this.isNextScheduleTriggered(this.nextScheduleItem); + if (shouldMoveToNext) { + postMessage(this.nextScheduleItem); + this.currentScheduleItem = { ...this.nextScheduleItem }; + this.nextScheduleItem = this.nextScheduleItem.next; + } + } + } + + // Restart the timer to continue polling + if (this.nextScheduleItem) { + this.timerId = setTimeout(() => this.runTimer(), TimingWorker.getRandomInterval()); + } + return; + } + + if (schedule) { + // Only initialize MR plugin if schedule contains MR sessions + const hasMRSessions = schedule.some((item) => item.mobileRiderSessionId); + if (hasMRSessions) { + await this.initializeMobileRider(); + await this.mobileRiderPlugin.initializeSessions(schedule); + + // Update conditions with MR session statuses + const mrConditions = {}; + this.mobileRiderPlugin.sessions.forEach((s, id) => { + mrConditions[`mr_session_${id}`] = s; + }); + + this.conditionStore = { + ...this.conditionStore, + ...conditions, + ...mrConditions, + }; + } else { + this.conditionStore = { ...this.conditionStore, ...conditions }; + } } if (testing.scheduleItemId) { @@ -190,6 +223,14 @@ class TimingWorker { this.runTimer(); } + async initializeMobileRider() { + if (!this.mobileRiderPlugin) { + const { default: MobileRiderPlugin } = await import('./mobile-rider-plugin.js'); + this.mobileRiderPlugin = new MobileRiderPlugin(); + } + return this.mobileRiderPlugin; + } + setupMessageHandler() { onmessage = (event) => this.handleMessage(event); } From 3e8e5b517b30a1f448531584fbf5bb0f4203b6fd Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Fri, 23 May 2025 14:26:34 -0400 Subject: [PATCH 17/93] Revert "WIP" This reverts commit a3ad3f1721152a66b21ca13858dfb7d35f6ac9f8. --- events/blocks/chrono-box/chrono-box.js | 50 +++++------- .../timing-framework/mobile-rider-plugin.js | 18 ----- events/features/timing-framework/worker.js | 79 +++++-------------- 3 files changed, 39 insertions(+), 108 deletions(-) diff --git a/events/blocks/chrono-box/chrono-box.js b/events/blocks/chrono-box/chrono-box.js index 954bf899..4269d170 100644 --- a/events/blocks/chrono-box/chrono-box.js +++ b/events/blocks/chrono-box/chrono-box.js @@ -77,6 +77,14 @@ export default async function init(el) { import(`${LIBS}/features/spectrum-web-components/dist/progress-circle.js`), ]); + // Check if MobileRider is enabled + const isMobileRiderEnabled = el.classList.contains('mobile-rider-enabled'); + + if (isMobileRiderEnabled) { + // Load MobileRider plugin + await import('../../features/timing-framework/mobile-rider-plugin.js'); + } + const blockConfig = readBlockConfig(el); const scheduleId = blockConfig?.['schedule-id']; let staticSchedule; @@ -96,19 +104,12 @@ export default async function init(el) { return; } - // Check if schedule contains any MR sessions - const hasMRSessions = thisSchedule.some((item) => item.mobileRiderSessionId); - - // Only add the class if MR sessions are present - if (hasMRSessions) { - el.classList.add('mobile-rider-enabled'); - } - el.innerHTML = ''; + const worker = setScheduleToScheduleWorker(thisSchedule); // Add periodic MR session status check - if (hasMRSessions) { + if (isMobileRiderEnabled) { setInterval(async () => { const sessionIds = thisSchedule .filter((item) => item.mobileRiderSessionId) @@ -124,27 +125,16 @@ export default async function init(el) { } el.addEventListener('worker-message', (e) => { - const { type, schedule, conditions, sessionId, status } = e.detail.data; - - if (type === 'mr_session_update') { - // Handle MR session status update - worker.postMessage({ - type: 'update_mr_status', - sessionId, - status, - timestamp: Date.now(), - }); - } else { - // Handle regular schedule/condition updates - worker.postMessage({ - schedule, - conditions, - testing: { - toggleTime: getToggleTimeFromParams(), - scheduleItemId: getScheduleItemFromParams(), - }, - }); - } + const { schedule, conditions } = e.detail.data; + + worker.postMessage({ + schedule, + conditions, + testing: { + toggleTime: getToggleTimeFromParams(), + scheduleItemId: getScheduleItemFromParams(), + }, + }); }); worker.onmessage = (event) => { diff --git a/events/features/timing-framework/mobile-rider-plugin.js b/events/features/timing-framework/mobile-rider-plugin.js index 7705c048..18fbc564 100644 --- a/events/features/timing-framework/mobile-rider-plugin.js +++ b/events/features/timing-framework/mobile-rider-plugin.js @@ -39,22 +39,4 @@ export default class MobileRiderPlugin { await this.fetchSessionStatus(sessionIds); } } - - static createSessionStatusEvent(sessionId, status) { - return new CustomEvent('worker-message', { - detail: { - data: { - type: 'mr_session_update', - sessionId, - status, - timestamp: Date.now(), - }, - }, - }); - } - - static dispatchSessionStatusEvent(element, sessionId, status) { - const event = this.createSessionStatusEvent(sessionId, status); - element.dispatchEvent(event); - } } diff --git a/events/features/timing-framework/worker.js b/events/features/timing-framework/worker.js index b3801002..09f8866c 100644 --- a/events/features/timing-framework/worker.js +++ b/events/features/timing-framework/worker.js @@ -1,10 +1,12 @@ +import MobileRiderPlugin from './mobile-rider-plugin.js'; + class TimingWorker { constructor() { this.conditionStore = null; this.currentScheduleItem = null; this.nextScheduleItem = null; this.timerId = null; - this.mobileRiderPlugin = null; + this.mobileRiderPlugin = new MobileRiderPlugin(); this.setupMessageHandler(); } @@ -94,9 +96,10 @@ class TimingWorker { isNextScheduleTriggered(scheduleItem) { if (!scheduleItem) return false; - // Only check MR conditions if plugin is initialized - if (this.mobileRiderPlugin && scheduleItem.mobileRiderSessionId) { + // Check if current item is an MR session + if (scheduleItem.mobileRiderSessionId) { const sessionStatus = this.conditionStore?.[`mr_session_${scheduleItem.mobileRiderSessionId}`]; + // If session is active, don't trigger next item if (sessionStatus === 'active') return false; } @@ -153,64 +156,28 @@ class TimingWorker { } async handleMessage(event) { - const { - type, schedule, conditions, sessionId, status, testing, - } = event.data; + const { schedule, conditions, testing } = event.data; if (this.timerId) { clearTimeout(this.timerId); this.timerId = null; } - if (type === 'update_mr_status') { - // Update condition store with new session status + if (schedule) { + // Initialize MR sessions if needed + await this.mobileRiderPlugin.initializeSessions(schedule); + + // Update conditions with MR session statuses + const mrConditions = {}; + this.mobileRiderPlugin.sessions.forEach((status, id) => { + mrConditions[`mr_session_${id}`] = status; + }); + this.conditionStore = { ...this.conditionStore, - [`mr_session_${sessionId}`]: status, + ...conditions, + ...mrConditions, }; - - // If current item is the updated session and it's now inactive, - // we need to re-evaluate the schedule - if (this.currentScheduleItem?.mobileRiderSessionId === sessionId && status === 'inactive') { - // Session has ended (underrun), check if we should move to next item - if (this.nextScheduleItem) { - const shouldMoveToNext = this.isNextScheduleTriggered(this.nextScheduleItem); - if (shouldMoveToNext) { - postMessage(this.nextScheduleItem); - this.currentScheduleItem = { ...this.nextScheduleItem }; - this.nextScheduleItem = this.nextScheduleItem.next; - } - } - } - - // Restart the timer to continue polling - if (this.nextScheduleItem) { - this.timerId = setTimeout(() => this.runTimer(), TimingWorker.getRandomInterval()); - } - return; - } - - if (schedule) { - // Only initialize MR plugin if schedule contains MR sessions - const hasMRSessions = schedule.some((item) => item.mobileRiderSessionId); - if (hasMRSessions) { - await this.initializeMobileRider(); - await this.mobileRiderPlugin.initializeSessions(schedule); - - // Update conditions with MR session statuses - const mrConditions = {}; - this.mobileRiderPlugin.sessions.forEach((s, id) => { - mrConditions[`mr_session_${id}`] = s; - }); - - this.conditionStore = { - ...this.conditionStore, - ...conditions, - ...mrConditions, - }; - } else { - this.conditionStore = { ...this.conditionStore, ...conditions }; - } } if (testing.scheduleItemId) { @@ -223,14 +190,6 @@ class TimingWorker { this.runTimer(); } - async initializeMobileRider() { - if (!this.mobileRiderPlugin) { - const { default: MobileRiderPlugin } = await import('./mobile-rider-plugin.js'); - this.mobileRiderPlugin = new MobileRiderPlugin(); - } - return this.mobileRiderPlugin; - } - setupMessageHandler() { onmessage = (event) => this.handleMessage(event); } From dda521724f669bb8fbce90e9368722137f25d651 Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Fri, 23 May 2025 14:26:46 -0400 Subject: [PATCH 18/93] Revert "MR refactor WIP" This reverts commit 53ef912eb994bea86158b3e721f0cd32fca80860. --- events/blocks/chrono-box/chrono-box.js | 24 ---------- .../timing-framework/mobile-rider-plugin.js | 42 ---------------- events/features/timing-framework/worker.js | 48 +++++-------------- 3 files changed, 11 insertions(+), 103 deletions(-) delete mode 100644 events/features/timing-framework/mobile-rider-plugin.js diff --git a/events/blocks/chrono-box/chrono-box.js b/events/blocks/chrono-box/chrono-box.js index 4269d170..b4e77691 100644 --- a/events/blocks/chrono-box/chrono-box.js +++ b/events/blocks/chrono-box/chrono-box.js @@ -77,14 +77,6 @@ export default async function init(el) { import(`${LIBS}/features/spectrum-web-components/dist/progress-circle.js`), ]); - // Check if MobileRider is enabled - const isMobileRiderEnabled = el.classList.contains('mobile-rider-enabled'); - - if (isMobileRiderEnabled) { - // Load MobileRider plugin - await import('../../features/timing-framework/mobile-rider-plugin.js'); - } - const blockConfig = readBlockConfig(el); const scheduleId = blockConfig?.['schedule-id']; let staticSchedule; @@ -108,22 +100,6 @@ export default async function init(el) { const worker = setScheduleToScheduleWorker(thisSchedule); - // Add periodic MR session status check - if (isMobileRiderEnabled) { - setInterval(async () => { - const sessionIds = thisSchedule - .filter((item) => item.mobileRiderSessionId) - .map((item) => item.mobileRiderSessionId); - - if (sessionIds.length > 0) { - worker.postMessage({ - type: 'update_mr_status', - sessionIds, - }); - } - }, 5000); // Check every 5 seconds - } - el.addEventListener('worker-message', (e) => { const { schedule, conditions } = e.detail.data; diff --git a/events/features/timing-framework/mobile-rider-plugin.js b/events/features/timing-framework/mobile-rider-plugin.js deleted file mode 100644 index 18fbc564..00000000 --- a/events/features/timing-framework/mobile-rider-plugin.js +++ /dev/null @@ -1,42 +0,0 @@ -export default class MobileRiderPlugin { - constructor() { - this.sessions = new Map(); // Store session statuses - this.baseUrl = 'https://overlay-admin-dev.mobilerider.com'; - } - - async fetchSessionStatus(sessionIds) { - try { - const response = await fetch(`${this.baseUrl}/api/media-status?ids=${sessionIds.join(',')}`); - const data = await response.json(); - - // Update session statuses - data.active.forEach((id) => this.sessions.set(id, 'active')); - data.inactive.forEach((id) => this.sessions.set(id, 'inactive')); - - return data; - } catch (error) { - window.lana?.log(`Error fetching MobileRider session status: ${JSON.stringify(error)}`); - return null; - } - } - - isSessionActive(sessionId) { - return this.sessions.get(sessionId) === 'active'; - } - - async initializeSessions(schedule) { - // Extract all MR session IDs from the schedule - const sessionIds = []; - let current = schedule; - while (current) { - if (current.mobileRiderSessionId) { - sessionIds.push(current.mobileRiderSessionId); - } - current = current.next; - } - - if (sessionIds.length > 0) { - await this.fetchSessionStatus(sessionIds); - } - } -} diff --git a/events/features/timing-framework/worker.js b/events/features/timing-framework/worker.js index 09f8866c..18a286aa 100644 --- a/events/features/timing-framework/worker.js +++ b/events/features/timing-framework/worker.js @@ -1,12 +1,9 @@ -import MobileRiderPlugin from './mobile-rider-plugin.js'; - class TimingWorker { constructor() { this.conditionStore = null; this.currentScheduleItem = null; this.nextScheduleItem = null; this.timerId = null; - this.mobileRiderPlugin = new MobileRiderPlugin(); this.setupMessageHandler(); } @@ -36,17 +33,6 @@ class TimingWorker { let pointer = scheduleRoot; let start = null; - // First, check if there's an active MR session that should take precedence - while (pointer) { - if (pointer.mobileRiderSessionId && cs[`mr_session_${pointer.mobileRiderSessionId}`] === 'active') { - return pointer; - } - pointer = pointer.next; - } - - // Reset pointer and continue with normal schedule logic - pointer = scheduleRoot; - // Scan phase 1: Fast forward through toggleTime-only while (pointer) { const { toggleTime: t } = pointer; @@ -95,14 +81,6 @@ class TimingWorker { */ isNextScheduleTriggered(scheduleItem) { if (!scheduleItem) return false; - - // Check if current item is an MR session - if (scheduleItem.mobileRiderSessionId) { - const sessionStatus = this.conditionStore?.[`mr_session_${scheduleItem.mobileRiderSessionId}`]; - // If session is active, don't trigger next item - if (sessionStatus === 'active') return false; - } - const { conditions: c, toggleTime: t } = scheduleItem; const currentTime = new Date().getTime(); @@ -155,7 +133,7 @@ class TimingWorker { this.timerId = setTimeout(() => this.runTimer(), TimingWorker.getRandomInterval()); } - async handleMessage(event) { + handleMessage(event) { const { schedule, conditions, testing } = event.data; if (this.timerId) { @@ -163,21 +141,17 @@ class TimingWorker { this.timerId = null; } - if (schedule) { - // Initialize MR sessions if needed - await this.mobileRiderPlugin.initializeSessions(schedule); - - // Update conditions with MR session statuses - const mrConditions = {}; - this.mobileRiderPlugin.sessions.forEach((status, id) => { - mrConditions[`mr_session_${id}`] = status; - }); + if (conditions) { + this.conditionStore = { ...this.conditionStore, ...conditions }; + } - this.conditionStore = { - ...this.conditionStore, - ...conditions, - ...mrConditions, - }; + if (schedule) { + this.nextScheduleItem = TimingWorker.getStartScheduleItem( + schedule, + this.conditionStore, + testing, + ); + this.currentScheduleItem = this.nextScheduleItem?.prev || schedule; } if (testing.scheduleItemId) { From 16d57a3767bd3ebb63299f47ea8a3d823bf3e779 Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Fri, 23 May 2025 21:49:05 -0400 Subject: [PATCH 19/93] extracting metadata and MR both as plugins --- events/blocks/chrono-box/chrono-box.js | 20 ++- .../plugins/metadata/plugin.js | 14 ++ .../mobile-rider/mobile-rider-controller.js | 147 ++++++++++++++++++ .../plugins/mobile-rider/plugin.js | 18 +++ 4 files changed, 196 insertions(+), 3 deletions(-) create mode 100644 events/features/timing-framework/plugins/metadata/plugin.js create mode 100644 events/features/timing-framework/plugins/mobile-rider/mobile-rider-controller.js create mode 100644 events/features/timing-framework/plugins/mobile-rider/plugin.js diff --git a/events/blocks/chrono-box/chrono-box.js b/events/blocks/chrono-box/chrono-box.js index b4e77691..3d4857bb 100644 --- a/events/blocks/chrono-box/chrono-box.js +++ b/events/blocks/chrono-box/chrono-box.js @@ -33,7 +33,7 @@ function getSchedule(scheduleId) { return thisSchedule; } -function conditionsPreCheck(schedule) { +function staticConditionsPreCheck(schedule) { const conditions = {}; const allMetadataConditionSchedules = schedule.filter((entry) => entry.conditions?.some((condition) => condition.source === 'metadata')); allMetadataConditionSchedules.forEach((s) => { @@ -54,7 +54,7 @@ function conditionsPreCheck(schedule) { function setScheduleToScheduleWorker(schedule) { const scheduleLinkedList = buildScheduleDoubleLinkedList(schedule); const worker = new Worker('/events/features/timing-framework/worker.js'); - const conditions = conditionsPreCheck(schedule); + const conditions = staticConditionsPreCheck(schedule); worker.postMessage({ message: 'schedule', @@ -69,6 +69,19 @@ function setScheduleToScheduleWorker(schedule) { return worker; } +async function initPlugins(schedule) { + const SUPPORTED_PLUGINS = ['mobile-rider', 'metadata']; + const pluginsNeeded = SUPPORTED_PLUGINS.filter((plugin) => schedule.some((item) => item[plugin])); + const plugins = await Promise.all(pluginsNeeded.map((plugin) => import(`../../features/timing-framework/plugins/${plugin}/plugin.js`))); + + const pluginsModules = new Map(); + plugins.forEach(async (plugin, index) => { + pluginsModules.set(pluginsNeeded[index], await plugin.init(schedule)); + }); + + return pluginsModules; +} + export default async function init(el) { const [{ default: loadFragment }, { createTag }] = await Promise.all([ import(`${LIBS}/blocks/fragment/fragment.js`), @@ -98,7 +111,8 @@ export default async function init(el) { el.innerHTML = ''; - const worker = setScheduleToScheduleWorker(thisSchedule); + const pluginsOutputs = await initPlugins(thisSchedule); + const worker = setScheduleToScheduleWorker(thisSchedule, pluginsOutputs); el.addEventListener('worker-message', (e) => { const { schedule, conditions } = e.detail.data; diff --git a/events/features/timing-framework/plugins/metadata/plugin.js b/events/features/timing-framework/plugins/metadata/plugin.js new file mode 100644 index 00000000..f4088a40 --- /dev/null +++ b/events/features/timing-framework/plugins/metadata/plugin.js @@ -0,0 +1,14 @@ +import { getMetadata } from '../../../../scripts/utils.js'; + +export const metadataStore = new Map(); + +export default function init(schedule) { + const allMetadataInSchedules = schedule.filter((entry) => entry.metadata); + allMetadataInSchedules.forEach((metadata) => { + metadata.forEach((m) => { + metadataStore.set(m.key, getMetadata(metadata.key)); + }); + }); + + return metadataStore; +} diff --git a/events/features/timing-framework/plugins/mobile-rider/mobile-rider-controller.js b/events/features/timing-framework/plugins/mobile-rider/mobile-rider-controller.js new file mode 100644 index 00000000..177df6af --- /dev/null +++ b/events/features/timing-framework/plugins/mobile-rider/mobile-rider-controller.js @@ -0,0 +1,147 @@ +/** + * MobileRider Controller + * Handles all interactions with the MobileRider API + */ +class MobileRiderController { + constructor() { + this.baseUrl = 'https://overlay-admin-dev.mobilerider.com'; + this.token = null; + } + + /** + * Authenticate with the MobileRider API + * @param {string} email - User email + * @param {string} password - User password + * @returns {Promise} - Authentication token + */ + async login(email, password) { + try { + const response = await fetch(`${this.baseUrl}/api/login`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ email, password }), + }); + + if (!response.ok) { + const error = await response.json(); + throw new Error(error.message || 'Login failed'); + } + + const data = await response.json(); + this.token = data.token; + return this.token; + } catch (error) { + window.lana?.log(`MobileRider login error: ${error.message}`); + throw error; + } + } + + /** + * Get the status of multiple media items + * @param {string[]} ids - Array of media IDs to check + * @returns {Promise<{active: string[], inactive: string[]}>} + */ + async getMediaStatus(ids) { + try { + const response = await fetch( + `${this.baseUrl}/api/media-status?ids=${ids.join(',')}`, + { + method: 'GET', + headers: this.getHeaders(), + }, + ); + + if (!response.ok) { + const error = await response.json(); + window.lana?.log(`MobileRider getMediaStatus error: ${JSON.stringify(error)}`); + throw new Error(error.message || 'Failed to get media status'); + } + + return await response.json(); + } catch (error) { + window.lana?.log(`MobileRider getMediaStatus error: ${error.message}`); + throw error; + } + } + + /** + * Toggle media items between active and inactive states + * @param {Object} params + * @param {string[]} params.active - Array of media IDs to activate + * @param {string[]} params.inactive - Array of media IDs to deactivate + * @returns {Promise>} + */ + async toggleVideos({ active = [], inactive = [] }) { + try { + const response = await fetch(`${this.baseUrl}/api/toggle-videos`, { + method: 'POST', + headers: this.getHeaders(), + body: JSON.stringify({ active, inactive }), + }); + + if (!response.ok) { + const error = await response.json(); + window.lana?.log(`MobileRider toggleVideos error: ${JSON.stringify(error)}`); + throw new Error(error.message || 'Failed to toggle videos'); + } + + return await response.json(); + } catch (error) { + window.lana?.log(`MobileRider toggleVideos error: ${error.message}`); + throw error; + } + } + + /** + * Get headers for authenticated requests + * @returns {Object} Headers object + */ + getHeaders() { + const headers = { 'Content-Type': 'application/json' }; + + if (this.token) { + headers.Authorization = `Bearer ${this.token}`; + } + + return headers; + } + + /** + * Check if a media item is active + * @param {string} id - Media ID to check + * @returns {Promise} + */ + async isMediaActive(id) { + try { + const { active } = await this.getMediaStatus([id]); + return active.includes(id); + } catch (error) { + window.lana?.log(`MobileRider isMediaActive error: ${error.message}`); + return false; + } + } + + /** + * Get status for multiple media items and return as a map + * @param {string[]} ids - Array of media IDs to check + * @returns {Promise>} Map of media ID to active status + */ + async getMediaStatusMap(ids) { + try { + const { active } = await this.getMediaStatus(ids); + const statusMap = new Map(); + + ids.forEach((id) => { + statusMap.set(id, active.includes(id)); + }); + + return statusMap; + } catch (error) { + window.lana?.log(`MobileRider getMediaStatusMap error: ${error.message}`); + // Return a map with all IDs set to false in case of error + return new Map(ids.map((id) => [id, false])); + } + } +} + +export default MobileRiderController; diff --git a/events/features/timing-framework/plugins/mobile-rider/plugin.js b/events/features/timing-framework/plugins/mobile-rider/plugin.js new file mode 100644 index 00000000..15481d05 --- /dev/null +++ b/events/features/timing-framework/plugins/mobile-rider/plugin.js @@ -0,0 +1,18 @@ +import MobileRiderController from './mobile-rider-controller.js'; + +export const mobileRiderStore = new Map(); + +export default function init(schedule) { + const controller = new MobileRiderController(); + + const mobileRiderSchedules = schedule.filter((entry) => entry.mobileRider); + mobileRiderSchedules.forEach((s) => { + s.mobileRider.forEach((condition) => { + const { sessionId } = condition; + const isActive = controller.isMediaActive(sessionId); + mobileRiderStore.set(sessionId, isActive); + }); + }); + + return mobileRiderStore; +} From a0c4468c59a1d85e0c3bdab7fe40dd2f5463a263 Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Fri, 23 May 2025 21:57:22 -0400 Subject: [PATCH 20/93] Update chrono-box.js --- events/blocks/chrono-box/chrono-box.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/events/blocks/chrono-box/chrono-box.js b/events/blocks/chrono-box/chrono-box.js index 3d4857bb..62adb908 100644 --- a/events/blocks/chrono-box/chrono-box.js +++ b/events/blocks/chrono-box/chrono-box.js @@ -75,9 +75,9 @@ async function initPlugins(schedule) { const plugins = await Promise.all(pluginsNeeded.map((plugin) => import(`../../features/timing-framework/plugins/${plugin}/plugin.js`))); const pluginsModules = new Map(); - plugins.forEach(async (plugin, index) => { + await Promise.all(plugins.map(async (plugin, index) => { pluginsModules.set(pluginsNeeded[index], await plugin.init(schedule)); - }); + })); return pluginsModules; } From 6a7686f4c3bef0f9f869f1fd78e1d4f60d67b6a8 Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Sat, 24 May 2025 13:34:07 -0400 Subject: [PATCH 21/93] timing framework new worker --- events/blocks/chrono-box/chrono-box.js | 64 ++++----- .../plugins/metadata/plugin.js | 21 ++- .../plugins/mobile-rider/plugin.js | 18 ++- events/features/timing-framework/worker.js | 132 ++++++++++-------- 4 files changed, 143 insertions(+), 92 deletions(-) diff --git a/events/blocks/chrono-box/chrono-box.js b/events/blocks/chrono-box/chrono-box.js index 62adb908..47b5dff8 100644 --- a/events/blocks/chrono-box/chrono-box.js +++ b/events/blocks/chrono-box/chrono-box.js @@ -33,33 +33,36 @@ function getSchedule(scheduleId) { return thisSchedule; } -function staticConditionsPreCheck(schedule) { - const conditions = {}; - const allMetadataConditionSchedules = schedule.filter((entry) => entry.conditions?.some((condition) => condition.source === 'metadata')); - allMetadataConditionSchedules.forEach((s) => { - s.conditions.forEach((condition) => { - const { key } = condition; - - const metadata = getMetadata(key); - - if (metadata) { - conditions[key] = metadata; - } - }); - }); +async function initPlugins(schedule) { + const SUPPORTED_PLUGINS = ['mobile-rider', 'metadata']; + const pluginsNeeded = SUPPORTED_PLUGINS.filter((plugin) => schedule.some((item) => item[plugin])); + const plugins = await Promise.all(pluginsNeeded.map((plugin) => import(`../../features/timing-framework/plugins/${plugin}/plugin.js`))); - return conditions; + const pluginsModules = new Map(); + await Promise.all(plugins.map(async (plugin, index) => { + const pluginName = pluginsNeeded[index].replace('-', ''); + pluginsModules.set(pluginName, await plugin.init(schedule)); + })); + + return pluginsModules; } -function setScheduleToScheduleWorker(schedule) { +function setScheduleToScheduleWorker(schedule, plugins) { const scheduleLinkedList = buildScheduleDoubleLinkedList(schedule); const worker = new Worker('/events/features/timing-framework/worker.js'); - const conditions = staticConditionsPreCheck(schedule); + + // Convert plugin instances to their serializable state + const pluginStates = Object.fromEntries( + Array.from(plugins.entries()).map(([name, plugin]) => [ + name, + Object.fromEntries(plugin), // Convert Map to plain object + ]), + ); worker.postMessage({ message: 'schedule', schedule: scheduleLinkedList, - conditions, + plugins: pluginStates, testing: { toggleTime: getToggleTimeFromParams(), scheduleItemId: getScheduleItemFromParams(), @@ -69,19 +72,6 @@ function setScheduleToScheduleWorker(schedule) { return worker; } -async function initPlugins(schedule) { - const SUPPORTED_PLUGINS = ['mobile-rider', 'metadata']; - const pluginsNeeded = SUPPORTED_PLUGINS.filter((plugin) => schedule.some((item) => item[plugin])); - const plugins = await Promise.all(pluginsNeeded.map((plugin) => import(`../../features/timing-framework/plugins/${plugin}/plugin.js`))); - - const pluginsModules = new Map(); - await Promise.all(plugins.map(async (plugin, index) => { - pluginsModules.set(pluginsNeeded[index], await plugin.init(schedule)); - })); - - return pluginsModules; -} - export default async function init(el) { const [{ default: loadFragment }, { createTag }] = await Promise.all([ import(`${LIBS}/blocks/fragment/fragment.js`), @@ -115,11 +105,19 @@ export default async function init(el) { const worker = setScheduleToScheduleWorker(thisSchedule, pluginsOutputs); el.addEventListener('worker-message', (e) => { - const { schedule, conditions } = e.detail.data; + const { schedule, plugins } = e.detail.data; + + // Convert plugin instances to their serializable state + const pluginStates = Object.fromEntries( + Array.from(plugins.entries()).map(([name, plugin]) => [ + name, + Object.fromEntries(plugin), // Convert Map to plain object + ]), + ); worker.postMessage({ schedule, - conditions, + plugins: pluginStates, testing: { toggleTime: getToggleTimeFromParams(), scheduleItemId: getScheduleItemFromParams(), diff --git a/events/features/timing-framework/plugins/metadata/plugin.js b/events/features/timing-framework/plugins/metadata/plugin.js index f4088a40..eb48e72a 100644 --- a/events/features/timing-framework/plugins/metadata/plugin.js +++ b/events/features/timing-framework/plugins/metadata/plugin.js @@ -1,12 +1,29 @@ import { getMetadata } from '../../../../scripts/utils.js'; -export const metadataStore = new Map(); +const store = new Map(); +const channel = new BroadcastChannel('metadata-store'); + +export const metadataStore = { + get(key) { + return store.get(key); + }, + + set(key, value) { + store.set(key, value); + channel.postMessage({ key, value }); + }, + + getAll() { + return Object.fromEntries(store); + }, +}; export default function init(schedule) { const allMetadataInSchedules = schedule.filter((entry) => entry.metadata); allMetadataInSchedules.forEach((metadata) => { metadata.forEach((m) => { - metadataStore.set(m.key, getMetadata(metadata.key)); + const value = getMetadata(metadata.key); + metadataStore.set(m.key, value); }); }); diff --git a/events/features/timing-framework/plugins/mobile-rider/plugin.js b/events/features/timing-framework/plugins/mobile-rider/plugin.js index 15481d05..da8a1141 100644 --- a/events/features/timing-framework/plugins/mobile-rider/plugin.js +++ b/events/features/timing-framework/plugins/mobile-rider/plugin.js @@ -1,6 +1,22 @@ import MobileRiderController from './mobile-rider-controller.js'; -export const mobileRiderStore = new Map(); +const store = new Map(); +const channel = new BroadcastChannel('mobile-rider-store'); + +export const mobileRiderStore = { + get(sessionId) { + return store.get(sessionId); + }, + + set(sessionId, isActive) { + store.set(sessionId, isActive); + channel.postMessage({ sessionId, isActive }); + }, + + getAll() { + return Object.fromEntries(store); + }, +}; export default function init(schedule) { const controller = new MobileRiderController(); diff --git a/events/features/timing-framework/worker.js b/events/features/timing-framework/worker.js index 18a286aa..41d9996d 100644 --- a/events/features/timing-framework/worker.js +++ b/events/features/timing-framework/worker.js @@ -1,12 +1,44 @@ class TimingWorker { constructor() { - this.conditionStore = null; this.currentScheduleItem = null; this.nextScheduleItem = null; this.timerId = null; + this.plugins = new Map(); + this.channels = new Map(); this.setupMessageHandler(); } + setupBroadcastChannels(plugins) { + // Close any existing channels + this.channels.forEach((channel) => channel.close()); + this.channels.clear(); + + // Only set up channels for enabled plugins + if (plugins.has('metadata')) { + const channel = new BroadcastChannel('metadata-store'); + channel.onmessage = (event) => { + const { key, value } = event.data; + const metadataStore = this.plugins.get('metadata'); + if (metadataStore) { + metadataStore.set(key, value); + } + }; + this.channels.set('metadata', channel); + } + + if (plugins.has('mobileRider')) { + const channel = new BroadcastChannel('mobile-rider-store'); + channel.onmessage = (event) => { + const { sessionId, isActive } = event.data; + const mobileRiderStore = this.plugins.get('mobileRider'); + if (mobileRiderStore) { + mobileRiderStore.set(sessionId, isActive); + } + }; + this.channels.set('mobileRider', channel); + } + } + /** * @returns {number} * @description Returns the current time from the API @@ -24,16 +56,14 @@ class TimingWorker { /** * @param {Object} scheduleRoot - * @param {Object} cs: conditionStore * @returns {Object} - * @description Returns the first schedule item that should be shown + * @description Returns the first schedule item that should be shown based on toggleTime */ - static getStartScheduleItem(scheduleRoot, cs, testing = {}) { + static getStartScheduleItem(scheduleRoot, testing = {}) { const currentTime = testing.toggleTime || new Date().getTime(); let pointer = scheduleRoot; let start = null; - // Scan phase 1: Fast forward through toggleTime-only while (pointer) { const { toggleTime: t } = pointer; const toggleTimePassed = typeof t !== 'number' || currentTime > t; @@ -44,24 +74,7 @@ class TimingWorker { pointer = pointer.next; } - // Scan Phase 2: Scan from last toggleTime match forward with condition checks - pointer = start || scheduleRoot; - - while (pointer) { - const { toggleTime: t, conditions: c } = pointer; - const toggleTimePassed = !t || currentTime > t; - const conditionsMet = !c || c.every(({ key: k, expectedValue: v }) => { - const val = cs?.[k]; - const isAny = v.trim().toLowerCase() === 'any' && !!val; - return isAny || val === v; - }); - - if (toggleTimePassed && conditionsMet) return pointer; - - pointer = pointer.next; - } - - return scheduleRoot; + return start || scheduleRoot; } /** @@ -77,51 +90,58 @@ class TimingWorker { /** * @param {Object} scheduleItem * @returns {boolean} - * @description Returns true if the next schedule item is triggered + * @description Returns true if the next schedule item should be triggered based on plugins */ - isNextScheduleTriggered(scheduleItem) { + async shouldTriggerNextSchedule(scheduleItem) { if (!scheduleItem) return false; - const { conditions: c, toggleTime: t } = scheduleItem; - const currentTime = new Date().getTime(); - - const toggleTimePassed = !t || currentTime > t; - const conditionsMet = !c || c.every(({ key: k, expectedValue: v }) => { - const conditionValue = this.conditionStore?.[k]; - const isAnyVal = v.trim().toLowerCase() === 'any' && !!conditionValue; - return isAnyVal || conditionValue === v; - }); + // Check if previous item has mobileRider that's still active (overrun) + if (this.currentScheduleItem?.mobileRider) { + const mobileRiderStore = this.plugins.get('mobileRider'); + if (mobileRiderStore) { + const { sessionId } = this.currentScheduleItem.mobileRider; + const isActive = mobileRiderStore.get(sessionId); + if (isActive) return false; // Wait for session to end + } + } - return toggleTimePassed && conditionsMet; - } + // Check if current item has mobileRider that's ended (underrun) + if (scheduleItem.mobileRider) { + const mobileRiderStore = this.plugins.get('mobileRider'); + if (mobileRiderStore) { + const { sessionId } = scheduleItem.mobileRider; + const isActive = mobileRiderStore.get(sessionId); + if (!isActive) return true; // Move on if session ended + } + } - /** - * @param {number} currentTime - * @returns {boolean} - * @description Returns true if the current time is valid - */ - static async validateTime(currentTime) { - const apiCurrentTime = await TimingWorker.getCurrentTimeFromAPI(); - const diff = apiCurrentTime - currentTime; + // Check metadata conditions if present + if (scheduleItem.metadata) { + const metadataStore = this.plugins.get('metadata'); + if (metadataStore) { + const { key, expectedValue } = scheduleItem.metadata; + const value = metadataStore.get(key); + if ((expectedValue && value !== expectedValue) || (!expectedValue && !value)) return false; + } + } - if (diff > 10000) { - window.alert('Sorry. Your local time is off by more than 10 seconds. Please check your system clock.'); - return false; + // If no plugins are blocking, check toggleTime + const { toggleTime: t } = scheduleItem; + if (t) { + const currentTime = new Date().getTime(); + return currentTime > t; } return true; } async runTimer() { - const triggered = this.isNextScheduleTriggered(this.nextScheduleItem); + const shouldTrigger = await this.shouldTriggerNextSchedule(this.nextScheduleItem); const { pathToFragment: currentPath } = this.currentScheduleItem; const { pathToFragment: nextPath, prev: nextPrev } = this.nextScheduleItem; - if (triggered && (nextPath !== currentPath || nextPrev === null)) { - // const timeValid = await this.validateTime(currentTime); - // if (!timeValid) return; - + if (shouldTrigger && (nextPath !== currentPath || nextPrev === null)) { postMessage(this.nextScheduleItem); this.currentScheduleItem = { ...this.nextScheduleItem }; @@ -134,21 +154,21 @@ class TimingWorker { } handleMessage(event) { - const { schedule, conditions, testing } = event.data; + const { schedule, plugins, testing } = event.data; if (this.timerId) { clearTimeout(this.timerId); this.timerId = null; } - if (conditions) { - this.conditionStore = { ...this.conditionStore, ...conditions }; + if (plugins) { + this.plugins = new Map(Object.entries(plugins)); + this.setupBroadcastChannels(this.plugins); } if (schedule) { this.nextScheduleItem = TimingWorker.getStartScheduleItem( schedule, - this.conditionStore, testing, ); this.currentScheduleItem = this.nextScheduleItem?.prev || schedule; From 5c2e8fdf2d32e2576a9ec01175a129cba277938d Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Sat, 24 May 2025 23:02:35 -0400 Subject: [PATCH 22/93] New Chrono Box and Timing Framework Ready for Alignment --- events/blocks/chrono-box/chrono-box.js | 21 --------------------- events/features/timing-framework/worker.js | 4 ++-- 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/events/blocks/chrono-box/chrono-box.js b/events/blocks/chrono-box/chrono-box.js index 47b5dff8..e832cab8 100644 --- a/events/blocks/chrono-box/chrono-box.js +++ b/events/blocks/chrono-box/chrono-box.js @@ -104,27 +104,6 @@ export default async function init(el) { const pluginsOutputs = await initPlugins(thisSchedule); const worker = setScheduleToScheduleWorker(thisSchedule, pluginsOutputs); - el.addEventListener('worker-message', (e) => { - const { schedule, plugins } = e.detail.data; - - // Convert plugin instances to their serializable state - const pluginStates = Object.fromEntries( - Array.from(plugins.entries()).map(([name, plugin]) => [ - name, - Object.fromEntries(plugin), // Convert Map to plain object - ]), - ); - - worker.postMessage({ - schedule, - plugins: pluginStates, - testing: { - toggleTime: getToggleTimeFromParams(), - scheduleItemId: getScheduleItemFromParams(), - }, - }); - }); - worker.onmessage = (event) => { const { pathToFragment } = event.data; diff --git a/events/features/timing-framework/worker.js b/events/features/timing-framework/worker.js index 41d9996d..37cce28e 100644 --- a/events/features/timing-framework/worker.js +++ b/events/features/timing-framework/worker.js @@ -59,7 +59,7 @@ class TimingWorker { * @returns {Object} * @description Returns the first schedule item that should be shown based on toggleTime */ - static getStartScheduleItem(scheduleRoot, testing = {}) { + static getStartScheduleItemByToggleTime(scheduleRoot, testing = {}) { const currentTime = testing.toggleTime || new Date().getTime(); let pointer = scheduleRoot; let start = null; @@ -167,7 +167,7 @@ class TimingWorker { } if (schedule) { - this.nextScheduleItem = TimingWorker.getStartScheduleItem( + this.nextScheduleItem = TimingWorker.getStartScheduleItemByToggleTime( schedule, testing, ); From c4473404cd095500655f03fa8132a6bade3f8b26 Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Tue, 27 May 2025 12:27:09 -0400 Subject: [PATCH 23/93] timing worker test added --- events/features/timing-framework/worker.js | 4 +- .../features/timing-framework/worker.test.js | 158 ++++++++++++++++++ 2 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 test/unit/features/timing-framework/worker.test.js diff --git a/events/features/timing-framework/worker.js b/events/features/timing-framework/worker.js index 37cce28e..75dfa660 100644 --- a/events/features/timing-framework/worker.js +++ b/events/features/timing-framework/worker.js @@ -174,7 +174,7 @@ class TimingWorker { this.currentScheduleItem = this.nextScheduleItem?.prev || schedule; } - if (testing.scheduleItemId) { + if (testing && testing.scheduleItemId) { this.nextScheduleItem = schedule.find((item) => item.id === testing.scheduleItemId); this.currentScheduleItem = this.nextScheduleItem?.prev || schedule; } @@ -191,3 +191,5 @@ class TimingWorker { // Initialize the worker (() => new TimingWorker())(); + +export default TimingWorker; diff --git a/test/unit/features/timing-framework/worker.test.js b/test/unit/features/timing-framework/worker.test.js new file mode 100644 index 00000000..1306e1bd --- /dev/null +++ b/test/unit/features/timing-framework/worker.test.js @@ -0,0 +1,158 @@ +import { expect } from '@esm-bundle/chai'; +import sinon from 'sinon'; +import TimingWorker from '../../../../events/features/timing-framework/worker.js'; + +// Mock BroadcastChannel +class MockBroadcastChannel { + constructor(name) { + this.name = name; + this.onmessage = null; + } + + postMessage(data) { + if (this.onmessage) { + this.onmessage({ data }); + } + } +} + +MockBroadcastChannel.prototype.close = () => {}; + +// Mock fetch +const mockFetch = sinon.stub(); +window.fetch = mockFetch; + +// Mock BroadcastChannel +window.BroadcastChannel = MockBroadcastChannel; + +describe('TimingWorker', () => { + let worker; + let mockPostMessage; + + beforeEach(() => { + // Reset mocks + sinon.reset(); + mockPostMessage = sinon.stub(); + window.postMessage = mockPostMessage; + + // Create a new worker instance + worker = new TimingWorker(); + }); + + describe('getStartScheduleItemByToggleTime', () => { + it('should return the first item if no toggleTime has passed', () => { + const schedule = { + toggleTime: Date.now() + 1000, + next: null, + }; + + const result = TimingWorker.getStartScheduleItemByToggleTime(schedule); + expect(result).to.equal(schedule); + }); + + it('should return the last passed item if toggleTime has passed', () => { + const now = Date.now(); + const schedule = { + toggleTime: now - 2000, + next: { + toggleTime: now - 1000, + next: { + toggleTime: now + 1000, + next: null, + }, + }, + }; + + const result = TimingWorker.getStartScheduleItemByToggleTime(schedule); + expect(result).to.equal(schedule.next); + }); + }); + + describe('shouldTriggerNextSchedule', () => { + it('should return false if scheduleItem is null', async () => { + const result = await worker.shouldTriggerNextSchedule(null); + expect(result).to.be.false; + }); + + it('should handle mobileRider overrun scenario', async () => { + const currentItem = { mobileRider: { sessionId: 'session1' } }; + const nextItem = { pathToFragment: '/next' }; + + worker.currentScheduleItem = currentItem; + worker.plugins.set('mobileRider', new Map([['session1', true]])); + + const result = await worker.shouldTriggerNextSchedule(nextItem); + expect(result).to.be.false; + }); + + it('should handle mobileRider underrun scenario', async () => { + const nextItem = { + mobileRider: { sessionId: 'session1' }, + pathToFragment: '/next', + }; + + worker.plugins.set('mobileRider', new Map([['session1', false]])); + + const result = await worker.shouldTriggerNextSchedule(nextItem); + expect(result).to.be.true; + }); + + it('should handle metadata conditions', async () => { + const nextItem = { + metadata: { key: 'testKey', expectedValue: 'expected' }, + pathToFragment: '/next', + }; + + worker.plugins.set('metadata', new Map([['testKey', 'expected']])); + + const result = await worker.shouldTriggerNextSchedule(nextItem); + expect(result).to.be.true; + }); + + it('should fall back to toggleTime if no plugins are blocking', async () => { + const now = Date.now(); + const nextItem = { + toggleTime: now - 1000, + pathToFragment: '/next', + }; + + const result = await worker.shouldTriggerNextSchedule(nextItem); + expect(result).to.be.true; + }); + }); + + describe('handleMessage', () => { + it('should set up plugins and channels', () => { + const plugins = { + metadata: { key1: 'value1' }, + mobileRider: { session1: true }, + }; + + worker.handleMessage({ + data: { + plugins, + schedule: { toggleTime: Date.now() }, + }, + }); + + expect(worker.plugins.size).to.equal(2); + expect(worker.channels.size).to.equal(2); + }); + + it('should handle testing.scheduleItemId', () => { + const schedule = [ + { id: '1', pathToFragment: '/1' }, + { id: '2', pathToFragment: '/2' }, + ]; + + worker.handleMessage({ + data: { + schedule, + testing: { scheduleItemId: '2' }, + }, + }); + + expect(worker.nextScheduleItem.id).to.equal('2'); + }); + }); +}); From 36bc8919a22e1f307106886bc1bf0ccf0d46e12d Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Tue, 27 May 2025 15:21:11 -0400 Subject: [PATCH 24/93] Added testing manager --- events/blocks/chrono-box/chrono-box.js | 11 +++--- events/features/timing-framework/testing.js | 29 +++++++++++----- events/features/timing-framework/worker.js | 37 ++++++++++++--------- 3 files changed, 47 insertions(+), 30 deletions(-) diff --git a/events/blocks/chrono-box/chrono-box.js b/events/blocks/chrono-box/chrono-box.js index e832cab8..d694df2c 100644 --- a/events/blocks/chrono-box/chrono-box.js +++ b/events/blocks/chrono-box/chrono-box.js @@ -1,4 +1,3 @@ -import { getToggleTimeFromParams, getScheduleItemFromParams } from '../../features/timing-framework/testing.js'; import { readBlockConfig, LIBS, getMetadata } from '../../scripts/utils.js'; function buildScheduleDoubleLinkedList(entries) { @@ -51,6 +50,11 @@ function setScheduleToScheduleWorker(schedule, plugins) { const scheduleLinkedList = buildScheduleDoubleLinkedList(schedule); const worker = new Worker('/events/features/timing-framework/worker.js'); + // Get testing data from URL params + const params = new URLSearchParams(document.location.search); + const testTiming = params.get('timing'); + const testing = testTiming ? { toggleTime: testTiming } : null; + // Convert plugin instances to their serializable state const pluginStates = Object.fromEntries( Array.from(plugins.entries()).map(([name, plugin]) => [ @@ -63,10 +67,7 @@ function setScheduleToScheduleWorker(schedule, plugins) { message: 'schedule', schedule: scheduleLinkedList, plugins: pluginStates, - testing: { - toggleTime: getToggleTimeFromParams(), - scheduleItemId: getScheduleItemFromParams(), - }, + testing, }); return worker; diff --git a/events/features/timing-framework/testing.js b/events/features/timing-framework/testing.js index daa28235..fc235bb3 100644 --- a/events/features/timing-framework/testing.js +++ b/events/features/timing-framework/testing.js @@ -1,11 +1,22 @@ -export function getToggleTimeFromParams() { - const params = new URLSearchParams(document.location.search); - const testTiming = params.get('timing'); - return testTiming; -} +export default class TestingManager { + constructor() { + this.timeOffset = 0; + this.isTestMode = false; + } + + init(testingData) { + if (testingData?.toggleTime) { + this.isTestMode = true; + const currentTime = new Date().getTime(); + this.timeOffset = testingData.toggleTime - currentTime; + } + } + + getAdjustedTime(currentTime) { + return this.isTestMode ? currentTime + this.timeOffset : currentTime; + } -export function getScheduleItemFromParams() { - const params = new URLSearchParams(document.location.search); - const scheduleItemId = params.get('scheduleItemId'); - return scheduleItemId; + isTesting() { + return this.isTestMode; + } } diff --git a/events/features/timing-framework/worker.js b/events/features/timing-framework/worker.js index 75dfa660..95bd56dd 100644 --- a/events/features/timing-framework/worker.js +++ b/events/features/timing-framework/worker.js @@ -1,3 +1,5 @@ +import TestingManager from './testing.js'; + class TimingWorker { constructor() { this.currentScheduleItem = null; @@ -5,6 +7,7 @@ class TimingWorker { this.timerId = null; this.plugins = new Map(); this.channels = new Map(); + this.testingManager = new TestingManager(); this.setupMessageHandler(); } @@ -55,12 +58,12 @@ class TimingWorker { } /** - * @param {Object} scheduleRoot + * @param {Object} scheduleRoot - The root of the schedule tree * @returns {Object} * @description Returns the first schedule item that should be shown based on toggleTime */ - static getStartScheduleItemByToggleTime(scheduleRoot, testing = {}) { - const currentTime = testing.toggleTime || new Date().getTime(); + static getStartScheduleItemByToggleTime(scheduleRoot) { + const currentTime = new Date().getTime(); let pointer = scheduleRoot; let start = null; @@ -87,6 +90,14 @@ class TimingWorker { return Math.floor(Math.random() * (max - min + 1)) + min; } + /** + * @returns {number} + * @description Returns the current time adjusted by the time offset if in test mode + */ + getCurrentTime() { + return this.testingManager.getAdjustedTime(new Date().getTime()); + } + /** * @param {Object} scheduleItem * @returns {boolean} @@ -126,10 +137,9 @@ class TimingWorker { } // If no plugins are blocking, check toggleTime - const { toggleTime: t } = scheduleItem; - if (t) { - const currentTime = new Date().getTime(); - return currentTime > t; + const { toggleTime } = scheduleItem; + if (toggleTime) { + return this.getCurrentTime() > toggleTime; } return true; @@ -161,21 +171,16 @@ class TimingWorker { this.timerId = null; } + // Initialize testing manager with testing data + this.testingManager.init(testing); + if (plugins) { this.plugins = new Map(Object.entries(plugins)); this.setupBroadcastChannels(this.plugins); } if (schedule) { - this.nextScheduleItem = TimingWorker.getStartScheduleItemByToggleTime( - schedule, - testing, - ); - this.currentScheduleItem = this.nextScheduleItem?.prev || schedule; - } - - if (testing && testing.scheduleItemId) { - this.nextScheduleItem = schedule.find((item) => item.id === testing.scheduleItemId); + this.nextScheduleItem = TimingWorker.getStartScheduleItemByToggleTime(schedule); this.currentScheduleItem = this.nextScheduleItem?.prev || schedule; } From 1f281ff5369a7658524987c3e9f867a6c566fd85 Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Tue, 27 May 2025 21:38:21 -0400 Subject: [PATCH 25/93] Testing logic extraction --- events/features/timing-framework/testing.js | 4 ++-- events/features/timing-framework/worker.js | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/events/features/timing-framework/testing.js b/events/features/timing-framework/testing.js index fc235bb3..4185a16f 100644 --- a/events/features/timing-framework/testing.js +++ b/events/features/timing-framework/testing.js @@ -12,8 +12,8 @@ export default class TestingManager { } } - getAdjustedTime(currentTime) { - return this.isTestMode ? currentTime + this.timeOffset : currentTime; + adjustTime(currentTime) { + return currentTime + this.timeOffset; } isTesting() { diff --git a/events/features/timing-framework/worker.js b/events/features/timing-framework/worker.js index 95bd56dd..80bffcf7 100644 --- a/events/features/timing-framework/worker.js +++ b/events/features/timing-framework/worker.js @@ -95,7 +95,10 @@ class TimingWorker { * @description Returns the current time adjusted by the time offset if in test mode */ getCurrentTime() { - return this.testingManager.getAdjustedTime(new Date().getTime()); + const currentTime = new Date().getTime(); + return this.testingManager.isTesting() + ? this.testingManager.adjustTime(currentTime) + : currentTime; } /** From 1704aa9e38b10e6f8869adbd113a5976b5c77aca Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Wed, 28 May 2025 11:35:14 +0530 Subject: [PATCH 26/93] updating marketo script --- rs/360-KCI-804/images/mktoTestFormConfig.js | 266 +++++++++++++++++++- 1 file changed, 263 insertions(+), 3 deletions(-) diff --git a/rs/360-KCI-804/images/mktoTestFormConfig.js b/rs/360-KCI-804/images/mktoTestFormConfig.js index b8611249..f422c490 100644 --- a/rs/360-KCI-804/images/mktoTestFormConfig.js +++ b/rs/360-KCI-804/images/mktoTestFormConfig.js @@ -1,3 +1,263 @@ -var mktoTestFormConfig = ` -#eyJmb3JtLnRlbXBsYXRlIjoicmVxdWVzdF9mb3JfaW5mb3JtYXRpb24iLCJmb3JtLnN1YnR5cGUiOiJyZXF1ZXN0X2Zvcl9pbmZvcm1hdGlvbiIsInByb2dyYW0uY2FtcGFpZ25pZHMuc2ZkYyI6IjcwMTE0MDAwMDAyWFl2SUFBVyIsInByb2dyYW0ucG9pIjoiTUFSS0VUT0VOR0FHRU1FTlRQTEFURk9STSIsImZvcm0uc3VjY2Vzcy5jb250ZW50IjoiaHR0cHM6Ly9idXNpbmVzcy5hZG9iZS5jb20vcmVzb3VyY2VzL2Vib29rcy9wcm92aW5nLXRoZS1pbXBhY3Qtb2YtbWFya2V0aW5nLW9uLXJldmVudWUvdGhhbmsteW91Lmh0bWwiLCJmb3JtLnN1Y2Nlc3MudHlwZSI6IiIsInByb2dyYW0uY29udGVudC50eXBlIjoiIiwicHJvZ3JhbS5jb250ZW50LmlkIjoiIiwiZmllbGRfdmlzaWJpbGl0eS5uYW1lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBob25lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnkiOiJyZXF1aXJlZCIsImZpZWxkX3Zpc2liaWxpdHkud2Vic2l0ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5mdW5jdGlvbmFsX2FyZWEiOiJGdW5jdGlvbmFsIEFyZWEtRFgiLCJmaWVsZF92aXNpYmlsaXR5LnN0YXRlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBvc3Rjb2RlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnlfc2l6ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5wcm9kdWN0cyI6ImhpZGRlbiIsImZpZWxkX2ZpbHRlcnMuaW5kdXN0cnkiOiJoaWRkZW4iLCJmaWVsZF9maWx0ZXJzLmpvYl9yb2xlIjoiYWxsIiwiZmllbGRfdmlzaWJpbGl0eS5jb21tZW50cyI6ImhpZGRlbiIsImZpZWxkX3Zpc2liaWxpdHkuZGVtbyI6ImhpZGRlbiIsInByb2dyYW0uY29wYXJ0bmVybmFtZXMiOiIiLCJwcm9ncmFtLmNhbXBhaWduaWRzLmV4dGVybmFsIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5yZXRvdWNoIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5vbnNpdGUiOiIiLCJwcm9ncmFtLmFkZGl0aW9uYWxfZm9ybV9pZCI6IiIsImZvcm0gaWQiOiIxNzIzIiwibWFya2V0byBtdW5ja2luIjoiMzYwLUtDSS04MDQiLCJtYXJrZXRvIGhvc3QiOiJlbmdhZ2UuYWRvYmUuY29tIiwiZm9ybSB0eXBlIjoibWFya2V0b19mb3JtIn0=) -`; \ No newline at end of file +// ## +// ## Test Module - Just a rough test module to set the config of the form. +// ## OVERRIDE THIS CONTENT WITH YOUR OWN VERSION +// ## + +if (typeof mkto_testing_loader != "function" && typeof mkto_testing_loader == "undefined") { + let resourceLocation = ".adobe-connect"; + let resourceWatch = '.adobe-connect button[daa-ll*="Join"]'; + let mkto_testing_loader = () => { + //hide Join button + + let cssFast = ` + button[daa-ll="Join the event-1--"] { + visibility: hidden !important; + opacity: 0 !important; + } + `; + let cssLinkFast = document.createElement("style"); + cssLinkFast.innerHTML = cssFast; + document.head.appendChild(cssLinkFast); + + const BASE_URL = "https://engage.marketo.com"; + const MUNCHKIN_ID = "360-KCI-804"; + + let formID = 3131; + let resourceFormHTML = ` +
+
+ + + +
+
+ `; + + const marketoCSSresource = "https://business.adobe.com/libs/blocks/marketo/marketo.css"; + + let marketoConfiguratorLink = + "eyJmb3JtLnRlbXBsYXRlIjoicmVxdWVzdF9mb3JfaW5mb3JtYXRpb24iLCJmb3JtLnN1YnR5cGUiOiJyZXF1ZXN0X2Zvcl9pbmZvcm1hdGlvbiIsInByb2dyYW0uY2FtcGFpZ25pZHMuc2ZkYyI6IjcwMTE0MDAwMDAyWFl2SUFBVyIsInByb2dyYW0ucG9pIjoiTUFSS0VUT0VOR0FHRU1FTlRQTEFURk9STSIsImZvcm0uc3VjY2Vzcy5jb250ZW50IjoiaHR0cHM6Ly9idXNpbmVzcy5hZG9iZS5jb20vcmVzb3VyY2VzL2Vib29rcy9wcm92aW5nLXRoZS1pbXBhY3Qtb2YtbWFya2V0aW5nLW9uLXJldmVudWUvdGhhbmsteW91Lmh0bWwiLCJmb3JtLnN1Y2Nlc3MudHlwZSI6IiIsInByb2dyYW0uY29udGVudC50eXBlIjoiIiwicHJvZ3JhbS5jb250ZW50LmlkIjoiIiwiZmllbGRfdmlzaWJpbGl0eS5uYW1lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBob25lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnkiOiJyZXF1aXJlZCIsImZpZWxkX3Zpc2liaWxpdHkud2Vic2l0ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5mdW5jdGlvbmFsX2FyZWEiOiJGdW5jdGlvbmFsIEFyZWEtRFgiLCJmaWVsZF92aXNpYmlsaXR5LnN0YXRlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBvc3Rjb2RlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnlfc2l6ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5wcm9kdWN0cyI6ImhpZGRlbiIsImZpZWxkX2ZpbHRlcnMuaW5kdXN0cnkiOiJoaWRkZW4iLCJmaWVsZF9maWx0ZXJzLmpvYl9yb2xlIjoiYWxsIiwiZmllbGRfdmlzaWJpbGl0eS5jb21tZW50cyI6ImhpZGRlbiIsImZpZWxkX3Zpc2liaWxpdHkuZGVtbyI6ImhpZGRlbiIsInByb2dyYW0uY29wYXJ0bmVybmFtZXMiOiIiLCJwcm9ncmFtLmNhbXBhaWduaWRzLmV4dGVybmFsIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5yZXRvdWNoIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5vbnNpdGUiOiIiLCJwcm9ncmFtLmFkZGl0aW9uYWxfZm9ybV9pZCI6IiIsImZvcm0gaWQiOiIxNzIzIiwibWFya2V0byBtdW5ja2luIjoiMzYwLUtDSS04MDQiLCJtYXJrZXRvIGhvc3QiOiJlbmdhZ2UuYWRvYmUuY29tIiwiZm9ybSB0eXBlIjoibWFya2V0b19mb3JtIn0"; + let marketoConfiguratorHTML = ` +
+ +
+
Marketo Configurator
+
+
+ `; + + let marketoConfiguratorJSON = {}; + try { + marketoConfiguratorJSON = JSON.parse( + decodeURIComponent(escape(window.atob(marketoConfiguratorLink))) + ); + } catch (e) { + console.error("Error parsing Marketo Configurator JSON", e); + } + + /* + Example of marktoConfiguratorJSON: + { + "form.template": "request_for_information", + "form.subtype": "request_for_information", + "program.campaignids.sfdc": "70114000002XYvIAAW", + "program.poi": "MARKETOENGAGEMENTPLATFORM", + "form.success.content": "https://business.adobe.com/resources/ebooks/proving-the-impact-of-marketing-on-revenue/thank-you.html", + "form.success.type": "", + "program.content.type": "", + "program.content.id": "", + "field_visibility.name": "required", + "field_visibility.phone": "required", + "field_visibility.company": "required", + "field_visibility.website": "required", + "field_filters.functional_area": "Functional Area-DX", + "field_visibility.state": "required", + "field_visibility.postcode": "required", + "field_visibility.company_size": "required", + "field_filters.products": "hidden", + "field_filters.industry": "hidden", + "field_filters.job_role": "all", + "field_visibility.comments": "hidden", + "field_visibility.demo": "hidden", + "program.copartnernames": "", + "program.campaignids.external": "", + "program.campaignids.retouch": "", + "program.campaignids.onsite": "", + "program.additional_form_id": "", + } + + + */ + + let use_marketoConfiguratorLink = false; + + let mcz_marketoForm_pref_local = { + "marketo munckin": "360-KCI-804", + "marketo host": "engage.adobe.com", + "form id": "1723", + form: { + template: "flex_event", + success: { + type: "adobe_connect", + content: "https://livekitqe.dev.adobeconnect.com/paxlkm0gwsj4", + delay: 5000, + confirm: false, + }, + baseSite: "https://business.adobe.com", + id: 3131, + }, + program: { + campaignids: { + sfdc: "7015Y000004BWOnQAO", + external: "", + retouch: "", + onsite: "", + cgen: "", + cuid: "", + }, + poi: "MARKETOENGAGEMENTPLATFORM", + additional_form_id: "", + copartnernames: "", + marketo_asset: { + name: "", + id: "", + }, + }, + field_visibility: { + name: "required", + phone: "hidden", + company: "visible", + website: "hidden", + state: "hidden", + postcode: "hidden", + }, + field_filters: { + functional_area: "Functional Area-DX", + products: "hidden", + industry: "hidden", + job_role: "hidden", + comments: "hidden", + demo: "hidden", + }, + }; + + if (use_marketoConfiguratorLink) { + for (let key in marketoConfiguratorJSON) { + let keyArray = key.split("."); + let obj = mcz_marketoForm_pref_local; + for (let i = 0; i < keyArray.length - 1; i++) { + if (!obj[keyArray[i]]) { + obj[keyArray[i]] = {}; + } + obj = obj[keyArray[i]]; + } + obj[keyArray[keyArray.length - 1]] = marketoConfiguratorJSON[key]; + } + } + + if (!window.location.search.includes("preview=1")) { + history.pushState({}, "", `${window.location.pathname}?preview=1`); + } + + window.mcz_marketoForm_pref = JSON.parse(JSON.stringify(mcz_marketoForm_pref_local)); + + var loadScript = (url, type, { mode } = {}) => + new Promise((resolve, reject) => { + let script = document.querySelector(`head > script[src="${url}"]`); + if (!script) { + const { head } = document; + script = document.createElement("script"); + script.setAttribute("src", url); + if (type) { + script.setAttribute("type", type); + } + if (["async", "defer"].includes(mode)) script.setAttribute(mode, true); + head.append(script); + } + + if (script.dataset.loaded) { + resolve(script); + return; + } + + const onScript = (event) => { + script.removeEventListener("load", onScript); + script.removeEventListener("error", onScript); + + if (event.type === "error") { + reject(new Error(`error loading script: ${script.src}`)); + } else if (event.type === "load") { + script.dataset.loaded = true; + resolve(script); + } + }; + + script.addEventListener("load", onScript); + script.addEventListener("error", onScript); + }); + + const resourceForm = document.createElement("div"); + resourceForm.innerHTML = resourceFormHTML; + if (document.querySelector(resourceLocation)) { + document.querySelector(resourceLocation).appendChild(resourceForm); + } else { + console.log("resourceLocation not found", resourceLocation); + } + + const cssLink = document.createElement("link"); + cssLink.rel = "stylesheet"; + cssLink.href = marketoCSSresource; + document.head.appendChild(cssLink); + + loadScript(`${BASE_URL}/js/forms2/js/forms2.min.js`) + .then(() => { + const { MktoForms2 } = window; + if (!MktoForms2) throw new Error("Marketo forms not loaded"); + + MktoForms2.loadForm(`${BASE_URL}`, MUNCHKIN_ID, formID); + MktoForms2.whenReady((form) => { + console.log("Marketo Form Thinks it's Ready", form); + }); + }) + .catch(() => { + console.error("Error loading Marketo form"); + }); + + window.mcz_marketoForm_adobe_connect_event = (event_url = "") => { + let final_url = ""; + if (event_url != "") { + final_url = event_url.trim(); + } + + if (document.querySelector(".marketo-form-wrapper")) { + document.querySelector(".marketo-form-wrapper").classList.add("hide"); + } + if (document.querySelector('.adobe-connect button[daa-ll*="Join"]')) { + document.querySelector('.adobe-connect button[daa-ll*="Join"]').click(); + } + console.log("adobe_connect_event", final_url); + }; + }; + + window.mkto_testing_loader = mkto_testing_loader; + let maxTries = 1000; + let checkResourceLocation = async () => { + if (maxTries <= 0) { + console.log("maxTries reached", maxTries); + return; + } + maxTries--; + if (document.querySelector(resourceWatch)) { + window.mkto_testing_loader(); + } else { + await new Promise((resolve) => setTimeout(resolve, 25)); + checkResourceLocation(); + } + }; + checkResourceLocation(); + } + + // ## + // ## \ No newline at end of file From 8b3a57af3fdbf681df50fe9dc39fd6f08ba7eb35 Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Wed, 28 May 2025 15:14:56 -0400 Subject: [PATCH 27/93] Update worker.test.js --- .../features/timing-framework/worker.test.js | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/test/unit/features/timing-framework/worker.test.js b/test/unit/features/timing-framework/worker.test.js index 1306e1bd..11de616b 100644 --- a/test/unit/features/timing-framework/worker.test.js +++ b/test/unit/features/timing-framework/worker.test.js @@ -138,21 +138,5 @@ describe('TimingWorker', () => { expect(worker.plugins.size).to.equal(2); expect(worker.channels.size).to.equal(2); }); - - it('should handle testing.scheduleItemId', () => { - const schedule = [ - { id: '1', pathToFragment: '/1' }, - { id: '2', pathToFragment: '/2' }, - ]; - - worker.handleMessage({ - data: { - schedule, - testing: { scheduleItemId: '2' }, - }, - }); - - expect(worker.nextScheduleItem.id).to.equal('2'); - }); }); }); From cdefc2b096faf55b40fa3d2040d7d6d3bff66c92 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Fri, 30 May 2025 13:03:11 +0530 Subject: [PATCH 28/93] Adding overlay --- events/blocks/adobe-connect/adobe-connect.js | 30 +++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/events/blocks/adobe-connect/adobe-connect.js b/events/blocks/adobe-connect/adobe-connect.js index 277f19e0..e54fc96f 100644 --- a/events/blocks/adobe-connect/adobe-connect.js +++ b/events/blocks/adobe-connect/adobe-connect.js @@ -37,7 +37,35 @@ export default async function init(el) { url = window.join_url; } url = addSearchParams(url, searchParams); - createTag('iframe', { src: url, frameborder: '0', allowfullscreen: 'true', class: 'fullwidth' }, '', { parent: el }); + + // Create overlay + const overlay = createTag('div', { + class: 'iframe-overlay', + style: 'position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.9); display: flex; align-items: center; justify-content: center; z-index: 1000;', + }); + + // Create loading text + const loadingText = createTag('div', { + style: 'font-size: 1.2em; color: #333;', + }, 'Loading event...'); + + overlay.appendChild(loadingText); + el.appendChild(overlay); + + // Create iframe + const iframe = createTag('iframe', { + src: url, + frameborder: '0', + allowfullscreen: 'true', + class: 'fullwidth', + style: 'position: relative; z-index: 1;', + }, '', { parent: el }); + + // Remove overlay after 7 seconds + setTimeout(() => { + overlay.remove(); + }, 7000); + button.remove(); document.body.querySelector('#webinar-marketo-form')?.remove(); }); From 1d4bff1b37f1c852db37431313ecf3e149e4e990 Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Mon, 2 Jun 2025 11:15:43 -0400 Subject: [PATCH 29/93] Remove non-prod API functions --- .../mobile-rider/mobile-rider-controller.js | 73 +------------------ 1 file changed, 1 insertion(+), 72 deletions(-) diff --git a/events/features/timing-framework/plugins/mobile-rider/mobile-rider-controller.js b/events/features/timing-framework/plugins/mobile-rider/mobile-rider-controller.js index 177df6af..9db55a33 100644 --- a/events/features/timing-framework/plugins/mobile-rider/mobile-rider-controller.js +++ b/events/features/timing-framework/plugins/mobile-rider/mobile-rider-controller.js @@ -5,35 +5,6 @@ class MobileRiderController { constructor() { this.baseUrl = 'https://overlay-admin-dev.mobilerider.com'; - this.token = null; - } - - /** - * Authenticate with the MobileRider API - * @param {string} email - User email - * @param {string} password - User password - * @returns {Promise} - Authentication token - */ - async login(email, password) { - try { - const response = await fetch(`${this.baseUrl}/api/login`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ email, password }), - }); - - if (!response.ok) { - const error = await response.json(); - throw new Error(error.message || 'Login failed'); - } - - const data = await response.json(); - this.token = data.token; - return this.token; - } catch (error) { - window.lana?.log(`MobileRider login error: ${error.message}`); - throw error; - } } /** @@ -47,7 +18,7 @@ class MobileRiderController { `${this.baseUrl}/api/media-status?ids=${ids.join(',')}`, { method: 'GET', - headers: this.getHeaders(), + headers: { 'Content-Type': 'application/json' }, }, ); @@ -64,48 +35,6 @@ class MobileRiderController { } } - /** - * Toggle media items between active and inactive states - * @param {Object} params - * @param {string[]} params.active - Array of media IDs to activate - * @param {string[]} params.inactive - Array of media IDs to deactivate - * @returns {Promise>} - */ - async toggleVideos({ active = [], inactive = [] }) { - try { - const response = await fetch(`${this.baseUrl}/api/toggle-videos`, { - method: 'POST', - headers: this.getHeaders(), - body: JSON.stringify({ active, inactive }), - }); - - if (!response.ok) { - const error = await response.json(); - window.lana?.log(`MobileRider toggleVideos error: ${JSON.stringify(error)}`); - throw new Error(error.message || 'Failed to toggle videos'); - } - - return await response.json(); - } catch (error) { - window.lana?.log(`MobileRider toggleVideos error: ${error.message}`); - throw error; - } - } - - /** - * Get headers for authenticated requests - * @returns {Object} Headers object - */ - getHeaders() { - const headers = { 'Content-Type': 'application/json' }; - - if (this.token) { - headers.Authorization = `Bearer ${this.token}`; - } - - return headers; - } - /** * Check if a media item is active * @param {string} id - Media ID to check From 8ce4e9be3c61dfa491958702e0fc9a02f83fe1ae Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Mon, 2 Jun 2025 13:43:44 -0400 Subject: [PATCH 30/93] Create README.md --- events/features/timing-framework/README.md | 335 +++++++++++++++++++++ 1 file changed, 335 insertions(+) create mode 100644 events/features/timing-framework/README.md diff --git a/events/features/timing-framework/README.md b/events/features/timing-framework/README.md new file mode 100644 index 00000000..5e8dd69b --- /dev/null +++ b/events/features/timing-framework/README.md @@ -0,0 +1,335 @@ +# Timing Framework + +The Timing Framework is a robust system for managing dynamic content scheduling and transitions in event pages. It works in conjunction with the Chronobox block and various plugins to provide precise control over content display timing. + +## Architecture Overview + +### Core Components + +1. **Chronobox Block** + - Entry point for the timing system + - Loads schedule from metadata or static configuration + - Dynamically imports and initializes required plugins + - Creates and manages the Timing Worker + - Handles fragment loading with loading states + +2. **Timing Worker** + - Web Worker that manages schedule processing + - Maintains current and next schedule items + - Handles time-based transitions with server-synchronized time + - Manages plugin state via BroadcastChannel + - Uses random intervals (500-1500ms) for polling to prevent thundering herd + +3. **Plugin System** + - Extensible architecture for custom timing conditions + - Currently supports: + - Mobile Rider Plugin: Manages mobile rider web player content + - Metadata Plugin: Handles metadata-based conditions + - Plugins communicate via BroadcastChannel + - Each plugin maintains its own state store + +### Data Flow + +1. **Schedule Definition** + ```json + { + "schedule-id": "unique-id", + "schedule": [ + { + "pathToFragment": "/path/to/fragment", + "toggleTime": 1234567890, + "mobileRider": { "sessionId": "session1" }, + "metadata": { "key": "value", "expectedValue": "expected" } + } + ] + } + ``` + +2. **Schedule Processing** + - Schedules are converted to a double-linked list for efficient traversal + - Each schedule item can have multiple conditions (time, plugins, metadata) + - Worker maintains current and next schedule items + - Initial position determined by `getStartScheduleItemByToggleTime` + +## Schedule Position Determination + +The framework uses a two-phase approach to determine the current schedule position: + +### Phase 1: Initial Time-based Position +The framework first determines the likely position based on `toggleTime` only, using `getStartScheduleItemByToggleTime`: + +```javascript +static getStartScheduleItemByToggleTime(scheduleRoot) { + const currentTime = new Date().getTime(); + let pointer = scheduleRoot; + let start = null; + + while (pointer) { + const { toggleTime: t } = pointer; + const toggleTimePassed = typeof t !== 'number' || currentTime > t; + + if (!toggleTimePassed) break; + + start = pointer; + pointer = pointer.next; + } + + return start || scheduleRoot; +} +``` + +This method: +- Traverses the schedule from the beginning +- Finds the last item whose `toggleTime` has passed +- Returns that item as the initial position +- Falls back to the first item if no time has passed + +### Phase 2: Context Validation +After finding the initial position, the framework then validates this position against other conditions: + +1. **Mobile Rider Status** + - If the initial position has an active MR session, it stays + - If the previous position has an active MR session, it may need to go back + +2. **Metadata Conditions** + - Validates metadata conditions for the initial position + - May need to adjust position if conditions aren't met + +This two-phase approach ensures: +- Quick initial positioning based on time +- Accurate final position based on all conditions +- Efficient handling of schedule navigation +- Proper handling of edge cases (like MR overrun) + +### Example + +```json +{ + "schedule": [ + { + "pathToFragment": "/pre-event", + "toggleTime": 1234567890 + }, + { + "pathToFragment": "/session1", + "toggleTime": 1234567899, + "mobileRider": { "sessionId": "session1" } + }, + { + "pathToFragment": "/post-event", + "toggleTime": 1234567908 + } + ] +} +``` + +If current time is 1234567900: +1. Phase 1: Finds "/session1" as initial position (last passed toggleTime) +2. Phase 2: + - Checks if session1 is still active + - If active, stays on "/session1" + - If ended, proceeds to "/post-event" + +## Schedule Trigger Mechanism + +The framework uses a sophisticated trigger system that considers multiple factors when determining when to transition between schedule items. The trigger evaluation happens in a specific order of precedence: + +### Trigger Evaluation Order + +1. **Mobile Rider (MR) Status** + - Overrun Check: If current item has MR and session is still active, stay on current item + - Underrun Check: If next item has MR and session has ended, proceed to next item + - MR takes precedence over time-based triggers + - Uses BroadcastChannel for real-time status updates + +2. **Metadata Conditions** + - Checks if metadata key matches expected value + - If condition not met, blocks transition regardless of time + - Can be used to force specific content based on external state + - Updates via BroadcastChannel for dynamic changes + +3. **Time-based Trigger (toggleTime)** + - Only evaluated if no MR or metadata conditions are blocking + - Uses server-synchronized time to prevent client clock manipulation + - Supports testing mode via URL parameters + - Random polling interval to prevent server load + +### Example Scenarios + +#### Scenario 1: Basic Time-based Transition +```json +{ + "schedule": [ + { + "pathToFragment": "/pre-event", + "toggleTime": 1234567890 + }, + { + "pathToFragment": "/during-event", + "toggleTime": 1234567899 + } + ] +} +``` +- At 1234567890: Transitions to "during-event" +- Simple time-based transition with no conditions +- Uses random polling interval (500-1500ms) + +#### Scenario 2: Mobile Rider Overrun +```json +{ + "schedule": [ + { + "pathToFragment": "/session1", + "toggleTime": 1234567890, + "mobileRider": { "sessionId": "session1" } + }, + { + "pathToFragment": "/session2", + "toggleTime": 1234567899 + } + ] +} +``` +- At 1234567890: Checks MR status via BroadcastChannel +- If session1 is still active: Stays on current content +- If session1 has ended: Proceeds to session2 +- Time trigger is ignored if MR session is active + +#### Scenario 3: Metadata-based Control +```json +{ + "schedule": [ + { + "pathToFragment": "/default", + "toggleTime": 1234567890, + "metadata": { "key": "eventStatus", "expectedValue": "active" } + }, + { + "pathToFragment": "/fallback", + "toggleTime": 1234567890 + } + ] +} +``` +- At 1234567890: Checks metadata condition via BroadcastChannel +- If eventStatus = "active": Shows default content +- If condition not met: Shows fallback content +- Time trigger is same for both, decision based on metadata + +#### Scenario 4: Combined Conditions +```json +{ + "schedule": [ + { + "pathToFragment": "/session1", + "toggleTime": 1234567890, + "mobileRider": { "sessionId": "session1" }, + "metadata": { "key": "streamStatus", "expectedValue": "live" } + }, + { + "pathToFragment": "/next", + "toggleTime": 1234567899 + } + ] +} +``` +- At 1234567890: Evaluates in order: + 1. Checks if session1 is still active (MR) + 2. If MR ended, checks if streamStatus = "live" + 3. If both conditions met, proceeds to next item + 4. If either condition fails, stays on current content + +### Testing + +The framework includes a testing system that allows: +- Time manipulation via URL parameters (`?timing=1234567890`) +- Simulation of plugin conditions via BroadcastChannel +- Testing of schedule transitions +- Server time synchronization testing + +## Error Handling + +The framework includes comprehensive error handling: +- Schedule parsing errors +- Plugin initialization failures +- Time synchronization issues +- Network errors during fragment loading + +All errors are logged via the Splunk LANA logging system for monitoring and debugging. + +## Technical Implementation Details + +### Web Worker Usage +The framework uses a Web Worker for schedule processing to: +- Keep the main thread responsive during schedule processing +- Prevent UI blocking during time checks and condition evaluations +- Handle schedule processing in parallel with UI updates +- Maintain consistent timing even under heavy main thread load + +[Web Worker Documentation](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers) + +Benefits: +- **Performance**: Schedule processing doesn't block the main thread +- **Reliability**: Time checks remain accurate even during UI updates +- **Scalability**: Can handle complex schedules without impacting page performance +- **Isolation**: Schedule logic is isolated from the main application + +### BroadcastChannel Communication +The framework uses BroadcastChannel for plugin communication to: +- Enable real-time updates across different parts of the application +- Allow plugins to communicate without tight coupling +- Support multiple instances of the timing framework +- Maintain state consistency across the application + +[BroadcastChannel Documentation](https://developer.mozilla.org/en-US/docs/Web/API/BroadcastChannel) + +Benefits: +- **Decoupling**: Plugins can communicate without direct dependencies +- **Real-time**: Immediate updates across all framework instances +- **Cross-context**: Works across different windows, tabs, and iframes +- **State Management**: Centralized state management for plugins + +### Implementation Example + +```javascript +// Worker setup +const worker = new Worker('/events/features/timing-framework/worker.js'); + +// Plugin communication via BroadcastChannel +const channel = new BroadcastChannel('metadata-store'); +channel.onmessage = (event) => { + const { key, value } = event.data; + // Handle plugin state updates +}; + +// Worker communication +worker.postMessage({ + message: 'schedule', + schedule: scheduleLinkedList, + plugins: pluginStates, + testing, +}); +``` + +### Why This Architecture? + +1. **Separation of Concerns** + - Schedule processing is isolated in the worker + - UI updates happen on the main thread + - Plugin state is managed via BroadcastChannel + +2. **Performance Optimization** + - Main thread stays responsive + - Schedule processing is non-blocking + - Real-time updates are efficient + +3. **Scalability** + - Can handle complex schedules + - Supports multiple plugin types + - Maintains performance under load + +4. **Reliability** + - Consistent timing checks + - Reliable state management + - Robust error handling From 9fe08e566adc13f3424a51c7bf6eea56c645d208 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Wed, 4 Jun 2025 17:57:45 +0530 Subject: [PATCH 31/93] Fetching Connect Url from Marketo Form Response --- events/blocks/adobe-connect/adobe-connect.js | 56 +++++++++++++++----- rs/360-KCI-804/images/mktoTestFormConfig.js | 26 ++++----- 2 files changed, 55 insertions(+), 27 deletions(-) diff --git a/events/blocks/adobe-connect/adobe-connect.js b/events/blocks/adobe-connect/adobe-connect.js index e54fc96f..f37f0eb9 100644 --- a/events/blocks/adobe-connect/adobe-connect.js +++ b/events/blocks/adobe-connect/adobe-connect.js @@ -2,6 +2,15 @@ import { LIBS } from '../../scripts/utils.js'; const { createTag } = await import(`${LIBS}/utils/utils.js`); +function validateUrl(url) { + try { + new URL(url); + return true; + } catch (_) { + return false; + } +} + function addParams(searchParams, params, key, value) { if (params.has(key)) { searchParams[key] = params.get(key); @@ -18,6 +27,16 @@ function addSearchParams(url, searchParams) { return urlObj.toString(); } +function getSearchParamsFromCuurentUrl() { + const params = new URL(window.location.href).searchParams; + const searchParams = {}; + addParams(searchParams, params, 'mkto_trk', 'marketo_tracker'); + addParams(searchParams, params, 'mkt_tok', 'marketo_token'); + addParams(searchParams, params, 'ecid', 'experience_cloud_id'); + addParams(searchParams, params, 'mkto_event_id', 'marketo_event_id'); + return searchParams; +} + export default async function init(el) { const h2 = el.querySelector('h2'); let url = h2?.textContent; @@ -26,14 +45,9 @@ export default async function init(el) { const button = createTag('button', { class: 'button' }, 'Join the event', { parent: el }); button.addEventListener('click', () => { - const params = new URL(window.location.href).searchParams; - const searchParams = {}; - addParams(searchParams, params, 'mkto_trk', 'marketo_tracker'); - addParams(searchParams, params, 'mkt_tok', 'marketo_token'); - addParams(searchParams, params, 'ecid', 'experience_cloud_id'); - addParams(searchParams, params, 'mkto_event_id', 'marketo_event_id'); + const searchParams = getSearchParamsFromCuurentUrl(); - if (window.join_url) { + if (validateUrl(window.join_url)) { url = window.join_url; } url = addSearchParams(url, searchParams); @@ -42,18 +56,15 @@ export default async function init(el) { const overlay = createTag('div', { class: 'iframe-overlay', style: 'position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.9); display: flex; align-items: center; justify-content: center; z-index: 1000;', - }); + }, '', { parent: el }); // Create loading text - const loadingText = createTag('div', { + createTag('div', { style: 'font-size: 1.2em; color: #333;', - }, 'Loading event...'); - - overlay.appendChild(loadingText); - el.appendChild(overlay); + }, 'Loading event...', { parent: overlay }); // Create iframe - const iframe = createTag('iframe', { + createTag('iframe', { src: url, frameborder: '0', allowfullscreen: 'true', @@ -69,4 +80,21 @@ export default async function init(el) { button.remove(); document.body.querySelector('#webinar-marketo-form')?.remove(); }); + + window.mcz_marketoForm_adobe_connect_event = (event_url = "") => { + let eventUrl = ""; + if (event_url != "") { + eventUrl = event_url.trim(); + window.join_url = eventUrl; + } + + if (document.querySelector(".marketo-form-wrapper")) { + document.querySelector(".marketo-form-wrapper").classList.add("hide"); + } + const joinButton = document.querySelector('.adobe-connect button[daa-ll*="Join"]'); + if (joinButton) { + document.querySelector('.adobe-connect button[daa-ll*="Join"]').click(); + } + console.log("adobe_connect_event in Events", eventUrl); + }; } diff --git a/rs/360-KCI-804/images/mktoTestFormConfig.js b/rs/360-KCI-804/images/mktoTestFormConfig.js index f422c490..feb33bd0 100644 --- a/rs/360-KCI-804/images/mktoTestFormConfig.js +++ b/rs/360-KCI-804/images/mktoTestFormConfig.js @@ -225,20 +225,20 @@ if (typeof mkto_testing_loader != "function" && typeof mkto_testing_loader == "u console.error("Error loading Marketo form"); }); - window.mcz_marketoForm_adobe_connect_event = (event_url = "") => { - let final_url = ""; - if (event_url != "") { - final_url = event_url.trim(); - } + // window.mcz_marketoForm_adobe_connect_event = (event_url = "") => { + // let final_url = ""; + // if (event_url != "") { + // final_url = event_url.trim(); + // } - if (document.querySelector(".marketo-form-wrapper")) { - document.querySelector(".marketo-form-wrapper").classList.add("hide"); - } - if (document.querySelector('.adobe-connect button[daa-ll*="Join"]')) { - document.querySelector('.adobe-connect button[daa-ll*="Join"]').click(); - } - console.log("adobe_connect_event", final_url); - }; + // if (document.querySelector(".marketo-form-wrapper")) { + // document.querySelector(".marketo-form-wrapper").classList.add("hide"); + // } + // if (document.querySelector('.adobe-connect button[daa-ll*="Join"]')) { + // document.querySelector('.adobe-connect button[daa-ll*="Join"]').click(); + // } + // console.log("adobe_connect_event", final_url); + // }; }; window.mkto_testing_loader = mkto_testing_loader; From 4029a9db923caf59752f86e6494081741be0817a Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Wed, 4 Jun 2025 18:09:27 +0530 Subject: [PATCH 32/93] typo fix --- events/blocks/adobe-connect/adobe-connect.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/events/blocks/adobe-connect/adobe-connect.js b/events/blocks/adobe-connect/adobe-connect.js index f37f0eb9..94b07033 100644 --- a/events/blocks/adobe-connect/adobe-connect.js +++ b/events/blocks/adobe-connect/adobe-connect.js @@ -27,7 +27,7 @@ function addSearchParams(url, searchParams) { return urlObj.toString(); } -function getSearchParamsFromCuurentUrl() { +function getSearchParamsFromCurrentUrl() { const params = new URL(window.location.href).searchParams; const searchParams = {}; addParams(searchParams, params, 'mkto_trk', 'marketo_tracker'); @@ -45,7 +45,7 @@ export default async function init(el) { const button = createTag('button', { class: 'button' }, 'Join the event', { parent: el }); button.addEventListener('click', () => { - const searchParams = getSearchParamsFromCuurentUrl(); + const searchParams = getSearchParamsFromCurrentUrl(); if (validateUrl(window.join_url)) { url = window.join_url; From a7a2ef3bddc0c4b5ccd84c05d9575f6c244ac29d Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Wed, 4 Jun 2025 18:58:19 +0530 Subject: [PATCH 33/93] Hiding join button --- events/blocks/adobe-connect/adobe-connect.css | 37 +++++++++++-------- events/blocks/adobe-connect/adobe-connect.js | 2 +- rs/360-KCI-804/images/mktoTestFormConfig.js | 26 ------------- 3 files changed, 22 insertions(+), 43 deletions(-) diff --git a/events/blocks/adobe-connect/adobe-connect.css b/events/blocks/adobe-connect/adobe-connect.css index 3364010c..33ed58ac 100644 --- a/events/blocks/adobe-connect/adobe-connect.css +++ b/events/blocks/adobe-connect/adobe-connect.css @@ -11,19 +11,24 @@ height: 900px; } - .adobe-connect button { - font-size: var(--type-body-s-size); - background-color: var(--link-color); - min-width: 114px; - height: 40px; - line-height: 20px; - padding: 9px 16px; - border: 0; - border-radius: 24px; - color: #fff; - font-weight: 700; - box-shadow: none; - margin: 0 auto; - cursor: pointer; - transition: background-color 0.13s, color 0.13s; - } \ No newline at end of file +.adobe-connect button { + font-size: var(--type-body-s-size); + background-color: var(--link-color); + min-width: 114px; + height: 40px; + line-height: 20px; + padding: 9px 16px; + border: 0; + border-radius: 24px; + color: #fff; + font-weight: 700; + box-shadow: none; + margin: 0 auto; + cursor: pointer; + transition: background-color 0.13s, color 0.13s; +} + +.adobe-connect .hidden { + visibility: hidden !important; + opacity: 0 !important; +} \ No newline at end of file diff --git a/events/blocks/adobe-connect/adobe-connect.js b/events/blocks/adobe-connect/adobe-connect.js index 94b07033..12724f2c 100644 --- a/events/blocks/adobe-connect/adobe-connect.js +++ b/events/blocks/adobe-connect/adobe-connect.js @@ -42,7 +42,7 @@ export default async function init(el) { let url = h2?.textContent; h2.remove(); - const button = createTag('button', { class: 'button' }, 'Join the event', { parent: el }); + const button = createTag('button', { class: 'hidden' }, 'Join the event', { parent: el }); button.addEventListener('click', () => { const searchParams = getSearchParamsFromCurrentUrl(); diff --git a/rs/360-KCI-804/images/mktoTestFormConfig.js b/rs/360-KCI-804/images/mktoTestFormConfig.js index feb33bd0..e7d9124c 100644 --- a/rs/360-KCI-804/images/mktoTestFormConfig.js +++ b/rs/360-KCI-804/images/mktoTestFormConfig.js @@ -7,17 +7,6 @@ if (typeof mkto_testing_loader != "function" && typeof mkto_testing_loader == "u let resourceLocation = ".adobe-connect"; let resourceWatch = '.adobe-connect button[daa-ll*="Join"]'; let mkto_testing_loader = () => { - //hide Join button - - let cssFast = ` - button[daa-ll="Join the event-1--"] { - visibility: hidden !important; - opacity: 0 !important; - } - `; - let cssLinkFast = document.createElement("style"); - cssLinkFast.innerHTML = cssFast; - document.head.appendChild(cssLinkFast); const BASE_URL = "https://engage.marketo.com"; const MUNCHKIN_ID = "360-KCI-804"; @@ -224,21 +213,6 @@ if (typeof mkto_testing_loader != "function" && typeof mkto_testing_loader == "u .catch(() => { console.error("Error loading Marketo form"); }); - - // window.mcz_marketoForm_adobe_connect_event = (event_url = "") => { - // let final_url = ""; - // if (event_url != "") { - // final_url = event_url.trim(); - // } - - // if (document.querySelector(".marketo-form-wrapper")) { - // document.querySelector(".marketo-form-wrapper").classList.add("hide"); - // } - // if (document.querySelector('.adobe-connect button[daa-ll*="Join"]')) { - // document.querySelector('.adobe-connect button[daa-ll*="Join"]').click(); - // } - // console.log("adobe_connect_event", final_url); - // }; }; window.mkto_testing_loader = mkto_testing_loader; From e8af965dd90f567e79bfa1fca23e20b8c9238888 Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Thu, 12 Jun 2025 11:57:20 -0400 Subject: [PATCH 34/93] Fixing toggleTime testing --- events/blocks/chrono-box/chrono-box.js | 1 - events/features/timing-framework/README.md | 22 +++++++++ events/features/timing-framework/worker.js | 3 ++ .../features/timing-framework/worker.test.js | 47 +++++++++++++++++++ 4 files changed, 72 insertions(+), 1 deletion(-) diff --git a/events/blocks/chrono-box/chrono-box.js b/events/blocks/chrono-box/chrono-box.js index d694df2c..e8e28000 100644 --- a/events/blocks/chrono-box/chrono-box.js +++ b/events/blocks/chrono-box/chrono-box.js @@ -64,7 +64,6 @@ function setScheduleToScheduleWorker(schedule, plugins) { ); worker.postMessage({ - message: 'schedule', schedule: scheduleLinkedList, plugins: pluginStates, testing, diff --git a/events/features/timing-framework/README.md b/events/features/timing-framework/README.md index 5e8dd69b..091f674f 100644 --- a/events/features/timing-framework/README.md +++ b/events/features/timing-framework/README.md @@ -248,6 +248,28 @@ The framework includes a testing system that allows: - Testing of schedule transitions - Server time synchronization testing +#### Testing Mode Behavior + +When testing mode is enabled via the `timing` URL parameter: + +1. **Time Simulation**: The framework simulates being at the specified EPOCH timestamp +2. **Polling Optimization**: Worker polling is disabled to show the exact state at that timestamp +3. **Schedule Positioning**: The schedule immediately jumps to the appropriate position based on the simulated time +4. **Plugin Testing**: Plugin conditions still work normally via BroadcastChannel + +**Example Usage:** +``` +https://your-site.com/event-page?timing=1640995200000 +``` + +This would simulate the page as if it were running at December 31, 2021 (timestamp 1640995200000), allowing you to: +- Test how content appears at specific moments +- Verify schedule positioning without waiting +- Debug timing-sensitive content transitions +- Test edge cases around schedule boundaries + +**Note**: In testing mode, the worker stops continuous polling since you're viewing a fixed point in time. This provides a more accurate representation of what users would see at that exact timestamp. + ## Error Handling The framework includes comprehensive error handling: diff --git a/events/features/timing-framework/worker.js b/events/features/timing-framework/worker.js index 80bffcf7..7754ebd2 100644 --- a/events/features/timing-framework/worker.js +++ b/events/features/timing-framework/worker.js @@ -163,6 +163,9 @@ class TimingWorker { if (!this.nextScheduleItem) return; + // Stop polling in testing mode - we want to see exact state at the simulated timestamp + if (this.testingManager.isTesting()) return; + this.timerId = setTimeout(() => this.runTimer(), TimingWorker.getRandomInterval()); } diff --git a/test/unit/features/timing-framework/worker.test.js b/test/unit/features/timing-framework/worker.test.js index 11de616b..3656ab4c 100644 --- a/test/unit/features/timing-framework/worker.test.js +++ b/test/unit/features/timing-framework/worker.test.js @@ -139,4 +139,51 @@ describe('TimingWorker', () => { expect(worker.channels.size).to.equal(2); }); }); + + describe('runTimer with testing', () => { + it('should stop polling when in testing mode', async () => { + const clock = sinon.useFakeTimers(); + + // Set up testing mode + worker.testingManager.init({ toggleTime: Date.now() + 1000 }); + + // Set up a schedule item that should trigger + worker.nextScheduleItem = { + toggleTime: Date.now() - 1000, + pathToFragment: '/test', + }; + worker.currentScheduleItem = { pathToFragment: '/current' }; + + // Run timer + await worker.runTimer(); + + // Verify no setTimeout was called (polling stopped) + expect(worker.timerId).to.be.null; + + clock.restore(); + }); + + it('should continue polling when not in testing mode', async () => { + const clock = sinon.useFakeTimers(); + + // Set up non-testing mode + worker.testingManager.init(null); + + // Set up a schedule item + worker.nextScheduleItem = { + toggleTime: Date.now() + 1000, + pathToFragment: '/test', + next: { toggleTime: Date.now() + 2000, pathToFragment: '/next' }, + }; + worker.currentScheduleItem = { pathToFragment: '/current' }; + + // Run timer + await worker.runTimer(); + + // Verify setTimeout was called (polling continues) + expect(worker.timerId).to.not.be.null; + + clock.restore(); + }); + }); }); From fde267b5350051d8f078834ba55a0f6781632825 Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Thu, 12 Jun 2025 23:54:47 -0400 Subject: [PATCH 35/93] Updated tab isolation --- events/features/timing-framework/README.md | 22 +++++++ events/features/timing-framework/worker.js | 23 ++++--- .../features/timing-framework/worker.test.js | 62 +++++++++++++++++++ 3 files changed, 99 insertions(+), 8 deletions(-) diff --git a/events/features/timing-framework/README.md b/events/features/timing-framework/README.md index 091f674f..3e437fca 100644 --- a/events/features/timing-framework/README.md +++ b/events/features/timing-framework/README.md @@ -312,6 +312,28 @@ Benefits: - **Cross-context**: Works across different windows, tabs, and iframes - **State Management**: Centralized state management for plugins +#### Tab Isolation +The framework implements tab isolation to prevent cross-tab interference: +- Each tab instance generates a unique UUID on initialization +- All BroadcastChannel messages include the sender's tab ID +- Messages are only processed if they originate from the same tab +- This prevents schedule transitions in one tab from affecting others + +Example message format: +```javascript +{ + tabId: "550e8400-e29b-41d4-a716-446655440000", + key: "eventStatus", + value: "active" +} +``` + +This isolation ensures: +- Independent testing in different tabs +- No interference between multiple event pages +- Clean separation of plugin states +- Predictable behavior in each tab + ### Implementation Example ```javascript diff --git a/events/features/timing-framework/worker.js b/events/features/timing-framework/worker.js index 7754ebd2..ae1aa1a1 100644 --- a/events/features/timing-framework/worker.js +++ b/events/features/timing-framework/worker.js @@ -8,6 +8,7 @@ class TimingWorker { this.plugins = new Map(); this.channels = new Map(); this.testingManager = new TestingManager(); + this.tabId = crypto.randomUUID(); this.setupMessageHandler(); } @@ -20,10 +21,13 @@ class TimingWorker { if (plugins.has('metadata')) { const channel = new BroadcastChannel('metadata-store'); channel.onmessage = (event) => { - const { key, value } = event.data; - const metadataStore = this.plugins.get('metadata'); - if (metadataStore) { - metadataStore.set(key, value); + const { tabId, key, value } = event.data; + // Only process messages from this tab + if (tabId === this.tabId) { + const metadataStore = this.plugins.get('metadata'); + if (metadataStore) { + metadataStore.set(key, value); + } } }; this.channels.set('metadata', channel); @@ -32,10 +36,13 @@ class TimingWorker { if (plugins.has('mobileRider')) { const channel = new BroadcastChannel('mobile-rider-store'); channel.onmessage = (event) => { - const { sessionId, isActive } = event.data; - const mobileRiderStore = this.plugins.get('mobileRider'); - if (mobileRiderStore) { - mobileRiderStore.set(sessionId, isActive); + const { tabId, sessionId, isActive } = event.data; + // Only process messages from this tab + if (tabId === this.tabId) { + const mobileRiderStore = this.plugins.get('mobileRider'); + if (mobileRiderStore) { + mobileRiderStore.set(sessionId, isActive); + } } }; this.channels.set('mobileRider', channel); diff --git a/test/unit/features/timing-framework/worker.test.js b/test/unit/features/timing-framework/worker.test.js index 3656ab4c..b02f268a 100644 --- a/test/unit/features/timing-framework/worker.test.js +++ b/test/unit/features/timing-framework/worker.test.js @@ -186,4 +186,66 @@ describe('TimingWorker', () => { clock.restore(); }); }); + + describe('BroadcastChannel handling', () => { + it('should only process messages from the same tab', () => { + const metadataWorker = new TimingWorker(); + const metadataStore = new Map(); + metadataWorker.plugins.set('metadata', metadataStore); + + // Set up the channel + metadataWorker.setupBroadcastChannels(new Set(['metadata'])); + const channel = metadataWorker.channels.get('metadata'); + + // Send message from different tab + channel.postMessage({ + tabId: 'different-tab-id', + key: 'testKey', + value: 'testValue', + }); + + // Value should not be set + expect(metadataStore.get('testKey')).to.be.undefined; + + // Send message from same tab + channel.postMessage({ + tabId: metadataWorker.tabId, + key: 'testKey', + value: 'testValue', + }); + + // Value should be set + expect(metadataStore.get('testKey')).to.equal('testValue'); + }); + + it('should handle mobile rider messages with tab isolation', () => { + const riderWorker = new TimingWorker(); + const mobileRiderStore = new Map(); + riderWorker.plugins.set('mobileRider', mobileRiderStore); + + // Set up the channel + riderWorker.setupBroadcastChannels(new Set(['mobileRider'])); + const channel = riderWorker.channels.get('mobileRider'); + + // Send message from different tab + channel.postMessage({ + tabId: 'different-tab-id', + sessionId: 'session1', + isActive: true, + }); + + // Session should not be set + expect(mobileRiderStore.get('session1')).to.be.undefined; + + // Send message from same tab + channel.postMessage({ + tabId: riderWorker.tabId, + sessionId: 'session1', + isActive: true, + }); + + // Session should be set + expect(mobileRiderStore.get('session1')).to.be.true; + }); + }); }); From e0b7704e6994d58c7414a44a86317b0eb0dd116f Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Fri, 13 Jun 2025 15:34:34 +0530 Subject: [PATCH 36/93] loading script directly --- head.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/head.html b/head.html index d7930281..c95acc62 100644 --- a/head.html +++ b/head.html @@ -2,7 +2,7 @@ - + From 763fbd25fb915b926df515a79c9f048fd326e353 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Fri, 13 Jun 2025 15:55:12 +0530 Subject: [PATCH 37/93] updating mktotestformconfig --- rs/360-KCI-804/images/mktoTestFormConfig.js | 438 ++++++++++---------- 1 file changed, 217 insertions(+), 221 deletions(-) diff --git a/rs/360-KCI-804/images/mktoTestFormConfig.js b/rs/360-KCI-804/images/mktoTestFormConfig.js index e7d9124c..223226ef 100644 --- a/rs/360-KCI-804/images/mktoTestFormConfig.js +++ b/rs/360-KCI-804/images/mktoTestFormConfig.js @@ -3,235 +3,231 @@ // ## OVERRIDE THIS CONTENT WITH YOUR OWN VERSION // ## -if (typeof mkto_testing_loader != "function" && typeof mkto_testing_loader == "undefined") { - let resourceLocation = ".adobe-connect"; - let resourceWatch = '.adobe-connect button[daa-ll*="Join"]'; - let mkto_testing_loader = () => { - - const BASE_URL = "https://engage.marketo.com"; - const MUNCHKIN_ID = "360-KCI-804"; - - let formID = 3131; - let resourceFormHTML = ` -
-
- - - -
+if (typeof mkto_testing_loader !== 'function' && typeof mkto_testing_loader === 'undefined') { + const resourceLocation = '.adobe-connect'; + const resourceWatch = '.adobe-connect button[daa-ll*="Join"]'; + const mkto_testing_loader = () => { + const BASE_URL = 'https://engage.marketo.com'; + const MUNCHKIN_ID = '360-KCI-804'; + + const formID = 3131; + const resourceFormHTML = ` +
+
+ + + +
+
+ `; + + const marketoCSSresource = 'https://business.adobe.com/libs/blocks/marketo/marketo.css'; + + const marketoConfiguratorLink = 'eyJmb3JtLnRlbXBsYXRlIjoicmVxdWVzdF9mb3JfaW5mb3JtYXRpb24iLCJmb3JtLnN1YnR5cGUiOiJyZXF1ZXN0X2Zvcl9pbmZvcm1hdGlvbiIsInByb2dyYW0uY2FtcGFpZ25pZHMuc2ZkYyI6IjcwMTE0MDAwMDAyWFl2SUFBVyIsInByb2dyYW0ucG9pIjoiTUFSS0VUT0VOR0FHRU1FTlRQTEFURk9STSIsImZvcm0uc3VjY2Vzcy5jb250ZW50IjoiaHR0cHM6Ly9idXNpbmVzcy5hZG9iZS5jb20vcmVzb3VyY2VzL2Vib29rcy9wcm92aW5nLXRoZS1pbXBhY3Qtb2YtbWFya2V0aW5nLW9uLXJldmVudWUvdGhhbmsteW91Lmh0bWwiLCJmb3JtLnN1Y2Nlc3MudHlwZSI6IiIsInByb2dyYW0uY29udGVudC50eXBlIjoiIiwicHJvZ3JhbS5jb250ZW50LmlkIjoiIiwiZmllbGRfdmlzaWJpbGl0eS5uYW1lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBob25lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnkiOiJyZXF1aXJlZCIsImZpZWxkX3Zpc2liaWxpdHkud2Vic2l0ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5mdW5jdGlvbmFsX2FyZWEiOiJGdW5jdGlvbmFsIEFyZWEtRFgiLCJmaWVsZF92aXNpYmlsaXR5LnN0YXRlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBvc3Rjb2RlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnlfc2l6ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5wcm9kdWN0cyI6ImhpZGRlbiIsImZpZWxkX2ZpbHRlcnMuaW5kdXN0cnkiOiJoaWRkZW4iLCJmaWVsZF9maWx0ZXJzLmpvYl9yb2xlIjoiYWxsIiwiZmllbGRfdmlzaWJpbGl0eS5jb21tZW50cyI6ImhpZGRlbiIsImZpZWxkX3Zpc2liaWxpdHkuZGVtbyI6ImhpZGRlbiIsInByb2dyYW0uY29wYXJ0bmVybmFtZXMiOiIiLCJwcm9ncmFtLmNhbXBhaWduaWRzLmV4dGVybmFsIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5yZXRvdWNoIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5vbnNpdGUiOiIiLCJwcm9ncmFtLmFkZGl0aW9uYWxfZm9ybV9pZCI6IiIsImZvcm0gaWQiOiIxNzIzIiwibWFya2V0byBtdW5ja2luIjoiMzYwLUtDSS04MDQiLCJtYXJrZXRvIGhvc3QiOiJlbmdhZ2UuYWRvYmUuY29tIiwiZm9ybSB0eXBlIjoibWFya2V0b19mb3JtIn0'; + const marketoConfiguratorHTML = ` +
+ - `; - - const marketoCSSresource = "https://business.adobe.com/libs/blocks/marketo/marketo.css"; - - let marketoConfiguratorLink = - "eyJmb3JtLnRlbXBsYXRlIjoicmVxdWVzdF9mb3JfaW5mb3JtYXRpb24iLCJmb3JtLnN1YnR5cGUiOiJyZXF1ZXN0X2Zvcl9pbmZvcm1hdGlvbiIsInByb2dyYW0uY2FtcGFpZ25pZHMuc2ZkYyI6IjcwMTE0MDAwMDAyWFl2SUFBVyIsInByb2dyYW0ucG9pIjoiTUFSS0VUT0VOR0FHRU1FTlRQTEFURk9STSIsImZvcm0uc3VjY2Vzcy5jb250ZW50IjoiaHR0cHM6Ly9idXNpbmVzcy5hZG9iZS5jb20vcmVzb3VyY2VzL2Vib29rcy9wcm92aW5nLXRoZS1pbXBhY3Qtb2YtbWFya2V0aW5nLW9uLXJldmVudWUvdGhhbmsteW91Lmh0bWwiLCJmb3JtLnN1Y2Nlc3MudHlwZSI6IiIsInByb2dyYW0uY29udGVudC50eXBlIjoiIiwicHJvZ3JhbS5jb250ZW50LmlkIjoiIiwiZmllbGRfdmlzaWJpbGl0eS5uYW1lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBob25lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnkiOiJyZXF1aXJlZCIsImZpZWxkX3Zpc2liaWxpdHkud2Vic2l0ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5mdW5jdGlvbmFsX2FyZWEiOiJGdW5jdGlvbmFsIEFyZWEtRFgiLCJmaWVsZF92aXNpYmlsaXR5LnN0YXRlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBvc3Rjb2RlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnlfc2l6ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5wcm9kdWN0cyI6ImhpZGRlbiIsImZpZWxkX2ZpbHRlcnMuaW5kdXN0cnkiOiJoaWRkZW4iLCJmaWVsZF9maWx0ZXJzLmpvYl9yb2xlIjoiYWxsIiwiZmllbGRfdmlzaWJpbGl0eS5jb21tZW50cyI6ImhpZGRlbiIsImZpZWxkX3Zpc2liaWxpdHkuZGVtbyI6ImhpZGRlbiIsInByb2dyYW0uY29wYXJ0bmVybmFtZXMiOiIiLCJwcm9ncmFtLmNhbXBhaWduaWRzLmV4dGVybmFsIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5yZXRvdWNoIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5vbnNpdGUiOiIiLCJwcm9ncmFtLmFkZGl0aW9uYWxfZm9ybV9pZCI6IiIsImZvcm0gaWQiOiIxNzIzIiwibWFya2V0byBtdW5ja2luIjoiMzYwLUtDSS04MDQiLCJtYXJrZXRvIGhvc3QiOiJlbmdhZ2UuYWRvYmUuY29tIiwiZm9ybSB0eXBlIjoibWFya2V0b19mb3JtIn0"; - let marketoConfiguratorHTML = ` -
- -
-
Marketo Configurator
-
+
+
Marketo Configurator
- `; - - let marketoConfiguratorJSON = {}; - try { - marketoConfiguratorJSON = JSON.parse( - decodeURIComponent(escape(window.atob(marketoConfiguratorLink))) - ); - } catch (e) { - console.error("Error parsing Marketo Configurator JSON", e); - } - - /* - Example of marktoConfiguratorJSON: - { - "form.template": "request_for_information", - "form.subtype": "request_for_information", - "program.campaignids.sfdc": "70114000002XYvIAAW", - "program.poi": "MARKETOENGAGEMENTPLATFORM", - "form.success.content": "https://business.adobe.com/resources/ebooks/proving-the-impact-of-marketing-on-revenue/thank-you.html", - "form.success.type": "", - "program.content.type": "", - "program.content.id": "", - "field_visibility.name": "required", - "field_visibility.phone": "required", - "field_visibility.company": "required", - "field_visibility.website": "required", - "field_filters.functional_area": "Functional Area-DX", - "field_visibility.state": "required", - "field_visibility.postcode": "required", - "field_visibility.company_size": "required", - "field_filters.products": "hidden", - "field_filters.industry": "hidden", - "field_filters.job_role": "all", - "field_visibility.comments": "hidden", - "field_visibility.demo": "hidden", - "program.copartnernames": "", - "program.campaignids.external": "", - "program.campaignids.retouch": "", - "program.campaignids.onsite": "", - "program.additional_form_id": "", - } - - - */ - - let use_marketoConfiguratorLink = false; - - let mcz_marketoForm_pref_local = { - "marketo munckin": "360-KCI-804", - "marketo host": "engage.adobe.com", - "form id": "1723", - form: { - template: "flex_event", - success: { - type: "adobe_connect", - content: "https://livekitqe.dev.adobeconnect.com/paxlkm0gwsj4", - delay: 5000, - confirm: false, - }, - baseSite: "https://business.adobe.com", - id: 3131, - }, - program: { - campaignids: { - sfdc: "7015Y000004BWOnQAO", - external: "", - retouch: "", - onsite: "", - cgen: "", - cuid: "", - }, - poi: "MARKETOENGAGEMENTPLATFORM", - additional_form_id: "", - copartnernames: "", - marketo_asset: { - name: "", - id: "", - }, +
+ `; + + let marketoConfiguratorJSON = {}; + try { + marketoConfiguratorJSON = JSON.parse( + decodeURIComponent(escape(window.atob(marketoConfiguratorLink))), + ); + } catch (e) { + console.error('Error parsing Marketo Configurator JSON', e); + } + + /* + Example of marktoConfiguratorJSON: + { + "form.template": "request_for_information", + "form.subtype": "request_for_information", + "program.campaignids.sfdc": "70114000002XYvIAAW", + "program.poi": "MARKETOENGAGEMENTPLATFORM", + "form.success.content": "https://business.adobe.com/resources/ebooks/proving-the-impact-of-marketing-on-revenue/thank-you.html", + "form.success.type": "", + "program.content.type": "", + "program.content.id": "", + "field_visibility.name": "required", + "field_visibility.phone": "required", + "field_visibility.company": "required", + "field_visibility.website": "required", + "field_filters.functional_area": "Functional Area-DX", + "field_visibility.state": "required", + "field_visibility.postcode": "required", + "field_visibility.company_size": "required", + "field_filters.products": "hidden", + "field_filters.industry": "hidden", + "field_filters.job_role": "all", + "field_visibility.comments": "hidden", + "field_visibility.demo": "hidden", + "program.copartnernames": "", + "program.campaignids.external": "", + "program.campaignids.retouch": "", + "program.campaignids.onsite": "", + "program.additional_form_id": "", + } + + */ + + const use_marketoConfiguratorLink = false; + + const mcz_marketoForm_pref_local = { + 'marketo munckin': '360-KCI-804', + 'marketo host': 'engage.adobe.com', + 'form id': '1723', + form: { + template: 'flex_event', + success: { + type: 'adobe_connect', + content: 'https://livekitqe.dev.adobeconnect.com/paxlkm0gwsj4', + delay: 5000, + confirm: false, }, - field_visibility: { - name: "required", - phone: "hidden", - company: "visible", - website: "hidden", - state: "hidden", - postcode: "hidden", + baseSite: 'https://business.adobe.com', + id: 3131, + }, + program: { + campaignids: { + sfdc: '7015Y000004BWOnQAO', + external: '', + retouch: '', + onsite: '', + cgen: '', + cuid: '', }, - field_filters: { - functional_area: "Functional Area-DX", - products: "hidden", - industry: "hidden", - job_role: "hidden", - comments: "hidden", - demo: "hidden", + poi: 'MARKETOENGAGEMENTPLATFORM', + additional_form_id: '', + copartnernames: '', + marketo_asset: { + name: '', + id: '', }, - }; - - if (use_marketoConfiguratorLink) { - for (let key in marketoConfiguratorJSON) { - let keyArray = key.split("."); - let obj = mcz_marketoForm_pref_local; - for (let i = 0; i < keyArray.length - 1; i++) { - if (!obj[keyArray[i]]) { - obj[keyArray[i]] = {}; - } - obj = obj[keyArray[i]]; + }, + field_visibility: { + name: 'required', + phone: 'hidden', + company: 'visible', + website: 'hidden', + state: 'hidden', + postcode: 'hidden', + }, + field_filters: { + functional_area: 'Functional Area-DX', + products: 'hidden', + industry: 'hidden', + job_role: 'hidden', + comments: 'hidden', + demo: 'hidden', + }, + }; + + if (use_marketoConfiguratorLink) { + for (const key in marketoConfiguratorJSON) { + const keyArray = key.split('.'); + let obj = mcz_marketoForm_pref_local; + for (let i = 0; i < keyArray.length - 1; i++) { + if (!obj[keyArray[i]]) { + obj[keyArray[i]] = {}; } - obj[keyArray[keyArray.length - 1]] = marketoConfiguratorJSON[key]; + obj = obj[keyArray[i]]; } + obj[keyArray[keyArray.length - 1]] = marketoConfiguratorJSON[key]; } - - if (!window.location.search.includes("preview=1")) { - history.pushState({}, "", `${window.location.pathname}?preview=1`); - } - - window.mcz_marketoForm_pref = JSON.parse(JSON.stringify(mcz_marketoForm_pref_local)); - - var loadScript = (url, type, { mode } = {}) => - new Promise((resolve, reject) => { - let script = document.querySelector(`head > script[src="${url}"]`); - if (!script) { - const { head } = document; - script = document.createElement("script"); - script.setAttribute("src", url); - if (type) { - script.setAttribute("type", type); - } - if (["async", "defer"].includes(mode)) script.setAttribute(mode, true); - head.append(script); - } - - if (script.dataset.loaded) { - resolve(script); - return; - } - - const onScript = (event) => { - script.removeEventListener("load", onScript); - script.removeEventListener("error", onScript); - - if (event.type === "error") { - reject(new Error(`error loading script: ${script.src}`)); - } else if (event.type === "load") { - script.dataset.loaded = true; - resolve(script); - } - }; - - script.addEventListener("load", onScript); - script.addEventListener("error", onScript); - }); - - const resourceForm = document.createElement("div"); - resourceForm.innerHTML = resourceFormHTML; - if (document.querySelector(resourceLocation)) { - document.querySelector(resourceLocation).appendChild(resourceForm); - } else { - console.log("resourceLocation not found", resourceLocation); + } + + if (!window.location.search.includes('preview=1')) { + history.pushState({}, '', `${window.location.pathname}?preview=1`); + } + + window.mcz_marketoForm_pref = JSON.parse(JSON.stringify(mcz_marketoForm_pref_local)); + + const loadScript = (url, type, { mode } = {}) => new Promise((resolve, reject) => { + let script = document.querySelector(`head > script[src="${url}"]`); + if (!script) { + const { head } = document; + script = document.createElement('script'); + script.setAttribute('src', url); + if (type) { + script.setAttribute('type', type); + } + if (['async', 'defer'].includes(mode)) script.setAttribute(mode, true); + head.append(script); } - - const cssLink = document.createElement("link"); - cssLink.rel = "stylesheet"; - cssLink.href = marketoCSSresource; - document.head.appendChild(cssLink); - - loadScript(`${BASE_URL}/js/forms2/js/forms2.min.js`) - .then(() => { - const { MktoForms2 } = window; - if (!MktoForms2) throw new Error("Marketo forms not loaded"); - - MktoForms2.loadForm(`${BASE_URL}`, MUNCHKIN_ID, formID); - MktoForms2.whenReady((form) => { - console.log("Marketo Form Thinks it's Ready", form); - }); - }) - .catch(() => { - console.error("Error loading Marketo form"); - }); - }; - - window.mkto_testing_loader = mkto_testing_loader; - let maxTries = 1000; - let checkResourceLocation = async () => { - if (maxTries <= 0) { - console.log("maxTries reached", maxTries); + + if (script.dataset.loaded) { + resolve(script); return; } - maxTries--; - if (document.querySelector(resourceWatch)) { - window.mkto_testing_loader(); - } else { - await new Promise((resolve) => setTimeout(resolve, 25)); - checkResourceLocation(); - } - }; - checkResourceLocation(); - } - - // ## - // ## \ No newline at end of file + + const onScript = (event) => { + script.removeEventListener('load', onScript); + script.removeEventListener('error', onScript); + + if (event.type === 'error') { + reject(new Error(`error loading script: ${script.src}`)); + } else if (event.type === 'load') { + script.dataset.loaded = true; + resolve(script); + } + }; + + script.addEventListener('load', onScript); + script.addEventListener('error', onScript); + }); + + const resourceForm = document.createElement('div'); + resourceForm.innerHTML = resourceFormHTML; + if (document.querySelector(resourceLocation)) { + document.querySelector(resourceLocation).appendChild(resourceForm); + } else { + console.log('resourceLocation not found', resourceLocation); + } + + const cssLink = document.createElement('link'); + cssLink.rel = 'stylesheet'; + cssLink.href = marketoCSSresource; + document.head.appendChild(cssLink); + + loadScript(`${BASE_URL}/js/forms2/js/forms2.min.js`) + .then(() => { + const { MktoForms2 } = window; + if (!MktoForms2) throw new Error('Marketo forms not loaded'); + + MktoForms2.loadForm(`${BASE_URL}`, MUNCHKIN_ID, formID); + MktoForms2.whenReady((form) => { + console.log("Marketo Form Thinks it's Ready", form); + }); + }) + .catch(() => { + console.error('Error loading Marketo form'); + }); + }; + + window.mkto_testing_loader = mkto_testing_loader; + let maxTries = 1000; + const checkResourceLocation = async () => { + if (maxTries <= 0) { + console.log('maxTries reached', maxTries); + return; + } + maxTries--; + if (document.querySelector(resourceWatch)) { + window.mkto_testing_loader(); + } else { + await new Promise((resolve) => setTimeout(resolve, 25)); + checkResourceLocation(); + } + }; + checkResourceLocation(); +} + +// ## +// ## From eb56491fede04b84ed740f7b3edf74846214f8f2 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Fri, 13 Jun 2025 15:56:04 +0530 Subject: [PATCH 38/93] Revert "loading script directly" This reverts commit e0b7704e6994d58c7414a44a86317b0eb0dd116f. --- head.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/head.html b/head.html index c95acc62..d7930281 100644 --- a/head.html +++ b/head.html @@ -2,7 +2,7 @@ - + From c7c50783ae7df35d76fb23603556cdfacb87e3dd Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Fri, 13 Jun 2025 15:56:46 +0530 Subject: [PATCH 39/93] removing version param --- head.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/head.html b/head.html index d7930281..31060e00 100644 --- a/head.html +++ b/head.html @@ -2,7 +2,7 @@ - + From ea31eef5ff80dac7703f43bb42a66f1af118dc68 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Fri, 20 Jun 2025 16:06:23 +0530 Subject: [PATCH 40/93] Incorporating the changes in testformconfig and adobe connect --- events/blocks/adobe-connect/adobe-connect.js | 54 ++- rs/360-KCI-804/images/mktoTestFormConfig.js | 357 ++++++++++++++----- 2 files changed, 320 insertions(+), 91 deletions(-) diff --git a/events/blocks/adobe-connect/adobe-connect.js b/events/blocks/adobe-connect/adobe-connect.js index 12724f2c..392d276e 100644 --- a/events/blocks/adobe-connect/adobe-connect.js +++ b/events/blocks/adobe-connect/adobe-connect.js @@ -40,6 +40,7 @@ function getSearchParamsFromCurrentUrl() { export default async function init(el) { const h2 = el.querySelector('h2'); let url = h2?.textContent; + el.setAttribute('data-mcz-dl-status', 'loading'); h2.remove(); const button = createTag('button', { class: 'hidden' }, 'Join the event', { parent: el }); @@ -49,6 +50,7 @@ export default async function init(el) { if (validateUrl(window.join_url)) { url = window.join_url; + console.log("join_url in Window", window.join_url); } url = addSearchParams(url, searchParams); @@ -81,20 +83,62 @@ export default async function init(el) { document.body.querySelector('#webinar-marketo-form')?.remove(); }); - window.mcz_marketoForm_adobe_connect_event = (event_url = "") => { - let eventUrl = ""; - if (event_url != "") { - eventUrl = event_url.trim(); + function mcz_marketoForm_adobe_connect_event2 = () => { + + if (window.mcz_marketoForm_pref?.form?.success?.type === "adobe_connect") { + const eventUrl = window.mcz_marketoForm_pref?.form?.success?.content; window.join_url = eventUrl; } if (document.querySelector(".marketo-form-wrapper")) { document.querySelector(".marketo-form-wrapper").classList.add("hide"); } + // console.log("adobe_connect_event in Events", eventUrl); + const joinButton = document.querySelector('.adobe-connect button[daa-ll*="Join"]'); if (joinButton) { document.querySelector('.adobe-connect button[daa-ll*="Join"]').click(); } - console.log("adobe_connect_event in Events", eventUrl); }; + + // Debounce function to limit rapid calls + function debounce(func, wait) { + let timeout; + return function executedFunction(...args) { + const later = () => { + clearTimeout(timeout); + func(...args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; + } + + // Debounced callback for observer + const debouncedCallback = debounce(() => { + const status = el.getAttribute('data-mcz-dl-status') + console.log('Attribute "data-mcz-dl-status" changed to', + el.getAttribute('data-mcz-dl-status')); + if (status === 'active') { + window.mcz_marketoForm_adobe_connect_event2(); + } + }, 300); // 300ms debounce delay + + const observer = new MutationObserver((mutationsList) => { + mutationsList.forEach((mutation) => { + if (mutation.type === 'attributes') { + debouncedCallback(); + } + }); + }); + + observer.observe(el, { + attributes: true, // Observe attribute changes + attributeFilter: ['data-mcz-dl-status'], // Optional: filter specific attributes + }); + + // Add debounce to sync and make it run only once + setTimeout(() => { + el.setAttribute('data-mcz-dl-status', 'loaded'); + }, 10000); } diff --git a/rs/360-KCI-804/images/mktoTestFormConfig.js b/rs/360-KCI-804/images/mktoTestFormConfig.js index 223226ef..6905a6ac 100644 --- a/rs/360-KCI-804/images/mktoTestFormConfig.js +++ b/rs/360-KCI-804/images/mktoTestFormConfig.js @@ -1,17 +1,55 @@ // ## // ## Test Module - Just a rough test module to set the config of the form. -// ## OVERRIDE THIS CONTENT WITH YOUR OWN VERSION // ## -if (typeof mkto_testing_loader !== 'function' && typeof mkto_testing_loader === 'undefined') { - const resourceLocation = '.adobe-connect'; - const resourceWatch = '.adobe-connect button[daa-ll*="Join"]'; - const mkto_testing_loader = () => { - const BASE_URL = 'https://engage.marketo.com'; - const MUNCHKIN_ID = '360-KCI-804'; +if (typeof mkto_testing_loader != "function" && typeof mkto_testing_loader == "undefined") { + function getMktToken() { + const storageKey = "mkt_tok"; + let mktToken = ""; - const formID = 3131; - const resourceFormHTML = ` + if (window.__mktTokVal && window.__mktTokVal?.trim()?.length > 0) { + return window.__mktTokVal; + } + + const urlParams = new URLSearchParams(window.location.search); + if (urlParams.has(storageKey)) { + mktToken = urlParams.get(storageKey); + try { + sessionStorage.setItem(storageKey, mktToken); + localStorage.setItem(storageKey, mktToken); + } catch (e) { + console.warn(`Could not save ${storageKey} to storage`, e); + } + } else { + mktToken = sessionStorage.getItem(storageKey) || localStorage.getItem(storageKey) || ""; + } + + window.__mktTokVal = mktToken; + return mktToken; + } + + window.getMktToken = getMktToken(); + + let resourceLocation = ".adobe-connect"; + let resourceWatch = '.adobe-connect button[daa-ll*="Join"]'; + let mkto_testing_loader = () => { + //hide Join button + + let cssFast = ` + button[daa-ll="Join the event-1--"] { + visibility: hidden !important; + opacity: 0 !important; + } + `; + let cssLinkFast = document.createElement("style"); + cssLinkFast.innerHTML = cssFast; + document.head.appendChild(cssLinkFast); + + const BASE_URL = "https://engage.marketo.com"; + const MUNCHKIN_ID = "360-KCI-804"; + + let formID = 3131; + let resourceFormHTML = `
@@ -21,10 +59,11 @@ if (typeof mkto_testing_loader !== 'function' && typeof mkto_testing_loader ===
`; - const marketoCSSresource = 'https://business.adobe.com/libs/blocks/marketo/marketo.css'; + const marketoCSSresource = "https://business.adobe.com/libs/blocks/marketo/marketo.css"; - const marketoConfiguratorLink = 'eyJmb3JtLnRlbXBsYXRlIjoicmVxdWVzdF9mb3JfaW5mb3JtYXRpb24iLCJmb3JtLnN1YnR5cGUiOiJyZXF1ZXN0X2Zvcl9pbmZvcm1hdGlvbiIsInByb2dyYW0uY2FtcGFpZ25pZHMuc2ZkYyI6IjcwMTE0MDAwMDAyWFl2SUFBVyIsInByb2dyYW0ucG9pIjoiTUFSS0VUT0VOR0FHRU1FTlRQTEFURk9STSIsImZvcm0uc3VjY2Vzcy5jb250ZW50IjoiaHR0cHM6Ly9idXNpbmVzcy5hZG9iZS5jb20vcmVzb3VyY2VzL2Vib29rcy9wcm92aW5nLXRoZS1pbXBhY3Qtb2YtbWFya2V0aW5nLW9uLXJldmVudWUvdGhhbmsteW91Lmh0bWwiLCJmb3JtLnN1Y2Nlc3MudHlwZSI6IiIsInByb2dyYW0uY29udGVudC50eXBlIjoiIiwicHJvZ3JhbS5jb250ZW50LmlkIjoiIiwiZmllbGRfdmlzaWJpbGl0eS5uYW1lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBob25lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnkiOiJyZXF1aXJlZCIsImZpZWxkX3Zpc2liaWxpdHkud2Vic2l0ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5mdW5jdGlvbmFsX2FyZWEiOiJGdW5jdGlvbmFsIEFyZWEtRFgiLCJmaWVsZF92aXNpYmlsaXR5LnN0YXRlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBvc3Rjb2RlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnlfc2l6ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5wcm9kdWN0cyI6ImhpZGRlbiIsImZpZWxkX2ZpbHRlcnMuaW5kdXN0cnkiOiJoaWRkZW4iLCJmaWVsZF9maWx0ZXJzLmpvYl9yb2xlIjoiYWxsIiwiZmllbGRfdmlzaWJpbGl0eS5jb21tZW50cyI6ImhpZGRlbiIsImZpZWxkX3Zpc2liaWxpdHkuZGVtbyI6ImhpZGRlbiIsInByb2dyYW0uY29wYXJ0bmVybmFtZXMiOiIiLCJwcm9ncmFtLmNhbXBhaWduaWRzLmV4dGVybmFsIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5yZXRvdWNoIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5vbnNpdGUiOiIiLCJwcm9ncmFtLmFkZGl0aW9uYWxfZm9ybV9pZCI6IiIsImZvcm0gaWQiOiIxNzIzIiwibWFya2V0byBtdW5ja2luIjoiMzYwLUtDSS04MDQiLCJtYXJrZXRvIGhvc3QiOiJlbmdhZ2UuYWRvYmUuY29tIiwiZm9ybSB0eXBlIjoibWFya2V0b19mb3JtIn0'; - const marketoConfiguratorHTML = ` + let marketoConfiguratorLink = + "eyJmb3JtLnRlbXBsYXRlIjoicmVxdWVzdF9mb3JfaW5mb3JtYXRpb24iLCJmb3JtLnN1YnR5cGUiOiJyZXF1ZXN0X2Zvcl9pbmZvcm1hdGlvbiIsInByb2dyYW0uY2FtcGFpZ25pZHMuc2ZkYyI6IjcwMTE0MDAwMDAyWFl2SUFBVyIsInByb2dyYW0ucG9pIjoiTUFSS0VUT0VOR0FHRU1FTlRQTEFURk9STSIsImZvcm0uc3VjY2Vzcy5jb250ZW50IjoiaHR0cHM6Ly9idXNpbmVzcy5hZG9iZS5jb20vcmVzb3VyY2VzL2Vib29rcy9wcm92aW5nLXRoZS1pbXBhY3Qtb2YtbWFya2V0aW5nLW9uLXJldmVudWUvdGhhbmsteW91Lmh0bWwiLCJmb3JtLnN1Y2Nlc3MudHlwZSI6IiIsInByb2dyYW0uY29udGVudC50eXBlIjoiIiwicHJvZ3JhbS5jb250ZW50LmlkIjoiIiwiZmllbGRfdmlzaWJpbGl0eS5uYW1lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBob25lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnkiOiJyZXF1aXJlZCIsImZpZWxkX3Zpc2liaWxpdHkud2Vic2l0ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5mdW5jdGlvbmFsX2FyZWEiOiJGdW5jdGlvbmFsIEFyZWEtRFgiLCJmaWVsZF92aXNpYmlsaXR5LnN0YXRlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBvc3Rjb2RlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnlfc2l6ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5wcm9kdWN0cyI6ImhpZGRlbiIsImZpZWxkX2ZpbHRlcnMuaW5kdXN0cnkiOiJoaWRkZW4iLCJmaWVsZF9maWx0ZXJzLmpvYl9yb2xlIjoiYWxsIiwiZmllbGRfdmlzaWJpbGl0eS5jb21tZW50cyI6ImhpZGRlbiIsImZpZWxkX3Zpc2liaWxpdHkuZGVtbyI6ImhpZGRlbiIsInByb2dyYW0uY29wYXJ0bmVybmFtZXMiOiIiLCJwcm9ncmFtLmNhbXBhaWduaWRzLmV4dGVybmFsIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5yZXRvdWNoIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5vbnNpdGUiOiIiLCJwcm9ncmFtLmFkZGl0aW9uYWxfZm9ybV9pZCI6IiIsImZvcm0gaWQiOiIxNzIzIiwibWFya2V0byBtdW5ja2luIjoiMzYwLUtDSS04MDQiLCJtYXJrZXRvIGhvc3QiOiJlbmdhZ2UuYWRvYmUuY29tIiwiZm9ybSB0eXBlIjoibWFya2V0b19mb3JtIn0"; + let marketoConfiguratorHTML = `
@@ -38,10 +77,10 @@ if (typeof mkto_testing_loader !== 'function' && typeof mkto_testing_loader === let marketoConfiguratorJSON = {}; try { marketoConfiguratorJSON = JSON.parse( - decodeURIComponent(escape(window.atob(marketoConfiguratorLink))), + decodeURIComponent(escape(window.atob(marketoConfiguratorLink))) ); } catch (e) { - console.error('Error parsing Marketo Configurator JSON', e); + console.error("Error parsing Marketo Configurator JSON", e); } /* @@ -75,63 +114,103 @@ if (typeof mkto_testing_loader !== 'function' && typeof mkto_testing_loader === "program.additional_form_id": "", } + */ - const use_marketoConfiguratorLink = false; + let use_marketoConfiguratorLink = false; - const mcz_marketoForm_pref_local = { - 'marketo munckin': '360-KCI-804', - 'marketo host': 'engage.adobe.com', - 'form id': '1723', + let mcz_marketoForm_pref_local = { + "marketo munckin": "360-KCI-804", + "marketo host": "engage.adobe.com", + "form id": "3131", form: { - template: 'flex_event', + template: "flex_event", success: { - type: 'adobe_connect', - content: 'https://livekitqe.dev.adobeconnect.com/paxlkm0gwsj4', + type: "adobe_connect", + content: "https://livekitqe.dev.adobeconnect.com/paxlkm0gwsj4", delay: 5000, confirm: false, }, - baseSite: 'https://business.adobe.com', + baseSite: "https://business.adobe.com", id: 3131, }, program: { campaignids: { - sfdc: '7015Y000004BWOnQAO', - external: '', - retouch: '', - onsite: '', - cgen: '', - cuid: '', + sfdc: "7015Y000004BWOnQAO", + external: "", + retouch: "", + onsite: "", + cgen: "", + cuid: "", }, - poi: 'MARKETOENGAGEMENTPLATFORM', - additional_form_id: '', - copartnernames: '', + poi: "MARKETOENGAGEMENTPLATFORM", + additional_form_id: "", + copartnernames: "", marketo_asset: { - name: '', - id: '', + name: "", + id: "", + }, + event: { + type: "adobe_connect", //connect_recording or video + subtype: "flex_event", + id: "mczac114328", + status: { + viewport: { + width: 1024, + height: 768, + active: true, + audio: true, + }, + activity: { + start: "2025-06-07-10:00", + end: "2025-06-07-10:00", + duration_ticks: 1000, + active_ticks: 1000, + log: [ + { + type: "adobe_connect", + subtype: "flex_event", + id: "ACTEST4242", + }, + ], + }, + activities: [], + }, + }, + status: { + label: "invited", + milestone: "responded", + is: "1001", + dateTime: "2025-06-07-10:00", + }, + status_previous: { + label: "invited", + milestone: "responded", + is: "1001", + dateTime: "2025-06-07-10:00", }, }, field_visibility: { - name: 'required', - phone: 'hidden', - company: 'visible', - website: 'hidden', - state: 'hidden', - postcode: 'hidden', + name: "required", + phone: "hidden", + company: "visible", + website: "hidden", + state: "hidden", + postcode: "hidden", }, field_filters: { - functional_area: 'Functional Area-DX', - products: 'hidden', - industry: 'hidden', - job_role: 'hidden', - comments: 'hidden', - demo: 'hidden', + functional_area: "Functional Area-DX", + products: "hidden", + industry: "hidden", + job_role: "hidden", + comments: "hidden", + demo: "hidden", }, }; if (use_marketoConfiguratorLink) { - for (const key in marketoConfiguratorJSON) { - const keyArray = key.split('.'); + for (let key in marketoConfiguratorJSON) { + let keyArray = key.split("."); let obj = mcz_marketoForm_pref_local; for (let i = 0; i < keyArray.length - 1; i++) { if (!obj[keyArray[i]]) { @@ -143,63 +222,64 @@ if (typeof mkto_testing_loader !== 'function' && typeof mkto_testing_loader === } } - if (!window.location.search.includes('preview=1')) { - history.pushState({}, '', `${window.location.pathname}?preview=1`); + if (!window.location.search.includes("preview=1")) { + history.pushState({}, "", `${window.location.pathname}?preview=1`); } window.mcz_marketoForm_pref = JSON.parse(JSON.stringify(mcz_marketoForm_pref_local)); - const loadScript = (url, type, { mode } = {}) => new Promise((resolve, reject) => { - let script = document.querySelector(`head > script[src="${url}"]`); - if (!script) { - const { head } = document; - script = document.createElement('script'); - script.setAttribute('src', url); - if (type) { - script.setAttribute('type', type); + var loadScript = (url, type, { mode } = {}) => + new Promise((resolve, reject) => { + let script = document.querySelector(`head > script[src="${url}"]`); + if (!script) { + const { head } = document; + script = document.createElement("script"); + script.setAttribute("src", url); + if (type) { + script.setAttribute("type", type); + } + if (["async", "defer"].includes(mode)) script.setAttribute(mode, true); + head.append(script); } - if (['async', 'defer'].includes(mode)) script.setAttribute(mode, true); - head.append(script); - } - - if (script.dataset.loaded) { - resolve(script); - return; - } - const onScript = (event) => { - script.removeEventListener('load', onScript); - script.removeEventListener('error', onScript); - - if (event.type === 'error') { - reject(new Error(`error loading script: ${script.src}`)); - } else if (event.type === 'load') { - script.dataset.loaded = true; + if (script.dataset.loaded) { resolve(script); + return; } - }; - script.addEventListener('load', onScript); - script.addEventListener('error', onScript); - }); + const onScript = (event) => { + script.removeEventListener("load", onScript); + script.removeEventListener("error", onScript); + + if (event.type === "error") { + reject(new Error(`error loading script: ${script.src}`)); + } else if (event.type === "load") { + script.dataset.loaded = true; + resolve(script); + } + }; + + script.addEventListener("load", onScript); + script.addEventListener("error", onScript); + }); - const resourceForm = document.createElement('div'); + const resourceForm = document.createElement("div"); resourceForm.innerHTML = resourceFormHTML; if (document.querySelector(resourceLocation)) { document.querySelector(resourceLocation).appendChild(resourceForm); } else { - console.log('resourceLocation not found', resourceLocation); + console.log("resourceLocation not found", resourceLocation); } - const cssLink = document.createElement('link'); - cssLink.rel = 'stylesheet'; + const cssLink = document.createElement("link"); + cssLink.rel = "stylesheet"; cssLink.href = marketoCSSresource; document.head.appendChild(cssLink); loadScript(`${BASE_URL}/js/forms2/js/forms2.min.js`) .then(() => { const { MktoForms2 } = window; - if (!MktoForms2) throw new Error('Marketo forms not loaded'); + if (!MktoForms2) throw new Error("Marketo forms not loaded"); MktoForms2.loadForm(`${BASE_URL}`, MUNCHKIN_ID, formID); MktoForms2.whenReady((form) => { @@ -207,15 +287,120 @@ if (typeof mkto_testing_loader !== 'function' && typeof mkto_testing_loader === }); }) .catch(() => { - console.error('Error loading Marketo form'); + console.error("Error loading Marketo form"); }); + + function sendRegSubmittedMessage() { + let iframe = document.getElementById("mcz-marketo-segment-iframe"); + if (iframe) { + iframe.contentWindow.postMessage({ type: "reg_submitted" }, "https://engage.adobe.com"); + } + } + + window.mcz_marketoForm_adobe_connect_event = (event_url = "") => { + let final_url = ""; + if (event_url != "") { + final_url = event_url.trim(); + } + + if (document.querySelector(".marketo-form-wrapper")) { + document.querySelector(".marketo-form-wrapper").classList.add("hide"); + } + if (document.querySelector('.adobe-connect button[daa-ll*="Join"]')) { + document.querySelector('.adobe-connect button[daa-ll*="Join"]').click(); + } + console.log("adobe_connect_event", final_url); + sendRegSubmittedMessage(); + }; + + function createProfileSyncIframe() { + let mktToken = getMktToken(); + let pageFromEventId = mcz_marketoForm_pref.program.event.id || ""; + if (pageFromEventId == "") { + console.log("No event id found, skipping profile sync iframe."); + return; + } + let baseURL = `https://engage.adobe.com/${pageFromEventId}.html`; + + if (mktToken) { + const iframe = document.createElement("iframe"); + let finalURL = `${baseURL}?mkt_tok=${mktToken}`; + + iframe.sandbox = "allow-scripts allow-same-origin"; + iframe.src = finalURL; + iframe.style.display = "none"; + iframe.id = "mcz-marketo-segment-iframe"; + document.body.appendChild(iframe); + console.log("Profile sync iframe added with URL:", iframe.src); + } else { + console.log(`No ${storageKey} found, skipping profile sync iframe.`); + } + } + + window.addEventListener("message", (event) => { + let config = { + allowedOrigins: ["https://engage.adobe.com", "https://business.adobe.com"], + }; + + let eventOrigin = new URL(event.origin); + let allowedToPass = false; + for (let i = 0; i < config.allowedOrigins.length; i++) { + let allowedOriginURL = new URL(config.allowedOrigins[i]); + if ( + eventOrigin.host === allowedOriginURL.host && + eventOrigin.protocol === allowedOriginURL.protocol && + eventOrigin.port === allowedOriginURL.port + ) { + allowedToPass = true; + break; + } + } + if (!allowedToPass) { + return; + } + //segment update + if (event.data && event.data.type === "profile_acc") { + console.log("Received profile data from iframe:", event.data); + if (event.data.mcz_marketoForm_pref) { + window.mcz_marketoForm_pref = window.mcz_marketoForm_pref || {}; + window.mcz_marketoForm_pref.profile = window.mcz_marketoForm_pref.profile || {}; + window.mcz_marketoForm_pref.profile.acc = event.data.mcz_marketoForm_pref; + } + } + //membership update + if (event.data && event.data.type === "program_profile") { + console.log("Received membership data from iframe:", event.data); + + let description = event.data.description || ""; + if (description == "") { + description = "program_profile"; + } + + if (event.data.mcz_marketoForm_pref) { + window.mcz_marketoForm_pref = window.mcz_marketoForm_pref || {}; + window.mcz_marketoForm_pref.program_profile = + window.mcz_marketoForm_pref.program_profile || {}; + + let dataLabel = "data-mcz-dl-status"; + let elements = document.querySelectorAll(`[${dataLabel}]`); + let timeNow = new Date().getTime(); + for (let i = 0; i < elements.length; i++) { + let element = elements[i]; + element.setAttribute(dataLabel, event.data.mcz_marketoForm_pref.program_profile.status); + element.setAttribute(`${dataLabel}-dt`, timeNow); + } + } + } + }); + + createProfileSyncIframe(); }; window.mkto_testing_loader = mkto_testing_loader; let maxTries = 1000; - const checkResourceLocation = async () => { + let checkResourceLocation = async () => { if (maxTries <= 0) { - console.log('maxTries reached', maxTries); + console.log("maxTries reached", maxTries); return; } maxTries--; From 4367c6834a5020f7e4591e03856791a111230149 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Fri, 20 Jun 2025 16:13:03 +0530 Subject: [PATCH 41/93] minor fix --- events/blocks/adobe-connect/adobe-connect.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/events/blocks/adobe-connect/adobe-connect.js b/events/blocks/adobe-connect/adobe-connect.js index 392d276e..30f5b6d5 100644 --- a/events/blocks/adobe-connect/adobe-connect.js +++ b/events/blocks/adobe-connect/adobe-connect.js @@ -83,7 +83,7 @@ export default async function init(el) { document.body.querySelector('#webinar-marketo-form')?.remove(); }); - function mcz_marketoForm_adobe_connect_event2 = () => { + function mcz_marketoForm_adobe_connect_event() { if (window.mcz_marketoForm_pref?.form?.success?.type === "adobe_connect") { const eventUrl = window.mcz_marketoForm_pref?.form?.success?.content; @@ -120,7 +120,7 @@ export default async function init(el) { console.log('Attribute "data-mcz-dl-status" changed to', el.getAttribute('data-mcz-dl-status')); if (status === 'active') { - window.mcz_marketoForm_adobe_connect_event2(); + window.mcz_marketoForm_adobe_connect_event(); } }, 300); // 300ms debounce delay From b45c5bb3c5c5b0dc958ea72bf517c7a6ea682094 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Fri, 20 Jun 2025 16:13:53 +0530 Subject: [PATCH 42/93] removing timeout --- events/blocks/adobe-connect/adobe-connect.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/events/blocks/adobe-connect/adobe-connect.js b/events/blocks/adobe-connect/adobe-connect.js index 30f5b6d5..5a733ab2 100644 --- a/events/blocks/adobe-connect/adobe-connect.js +++ b/events/blocks/adobe-connect/adobe-connect.js @@ -136,9 +136,4 @@ export default async function init(el) { attributes: true, // Observe attribute changes attributeFilter: ['data-mcz-dl-status'], // Optional: filter specific attributes }); - - // Add debounce to sync and make it run only once - setTimeout(() => { - el.setAttribute('data-mcz-dl-status', 'loaded'); - }, 10000); } From 355019755266ce78946824ea8a968ee9edf1bb88 Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Mon, 23 Jun 2025 12:10:24 -0400 Subject: [PATCH 43/93] Update worker.js --- events/features/timing-framework/worker.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/events/features/timing-framework/worker.js b/events/features/timing-framework/worker.js index ae1aa1a1..23475d9c 100644 --- a/events/features/timing-framework/worker.js +++ b/events/features/timing-framework/worker.js @@ -142,7 +142,12 @@ class TimingWorker { if (metadataStore) { const { key, expectedValue } = scheduleItem.metadata; const value = metadataStore.get(key); - if ((expectedValue && value !== expectedValue) || (!expectedValue && !value)) return false; + + const isEmpty = !value + || (Array.isArray(value) && value.length === 0) + || (typeof value === 'object' && Object.keys(value).length === 0); + const isAnyVal = expectedValue.trim().toLowerCase() === 'any' && !isEmpty; + return isAnyVal || value === expectedValue; } } From 7f9d1e555fc9081078ce9927d39134fc3c1d323e Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Mon, 23 Jun 2025 12:10:43 -0400 Subject: [PATCH 44/93] add metadata deep query --- events/features/timing-framework/plugins/metadata/plugin.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/events/features/timing-framework/plugins/metadata/plugin.js b/events/features/timing-framework/plugins/metadata/plugin.js index eb48e72a..c3fb8dcd 100644 --- a/events/features/timing-framework/plugins/metadata/plugin.js +++ b/events/features/timing-framework/plugins/metadata/plugin.js @@ -1,4 +1,4 @@ -import { getMetadata } from '../../../../scripts/utils.js'; +import { parseMetadataPath } from '../../../../scripts/utils.js'; const store = new Map(); const channel = new BroadcastChannel('metadata-store'); @@ -22,7 +22,7 @@ export default function init(schedule) { const allMetadataInSchedules = schedule.filter((entry) => entry.metadata); allMetadataInSchedules.forEach((metadata) => { metadata.forEach((m) => { - const value = getMetadata(metadata.key); + const value = parseMetadataPath(metadata.key); metadataStore.set(m.key, value); }); }); From 6fd7cf0aea7cf09a6ccc8dd956754dc85e7c8d8b Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Tue, 24 Jun 2025 11:43:36 -0400 Subject: [PATCH 45/93] Fix module import type --- events/blocks/chrono-box/chrono-box.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/events/blocks/chrono-box/chrono-box.js b/events/blocks/chrono-box/chrono-box.js index e8e28000..9663c127 100644 --- a/events/blocks/chrono-box/chrono-box.js +++ b/events/blocks/chrono-box/chrono-box.js @@ -48,7 +48,7 @@ async function initPlugins(schedule) { function setScheduleToScheduleWorker(schedule, plugins) { const scheduleLinkedList = buildScheduleDoubleLinkedList(schedule); - const worker = new Worker('/events/features/timing-framework/worker.js'); + const worker = new Worker('/events/features/timing-framework/worker.js', { type: 'module' }); // Get testing data from URL params const params = new URLSearchParams(document.location.search); From b2363b162f674e571fd74b99512190427bfa0098 Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Tue, 24 Jun 2025 11:51:35 -0400 Subject: [PATCH 46/93] Fix defaulting to first item issue --- events/features/timing-framework/worker.js | 28 ++++++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/events/features/timing-framework/worker.js b/events/features/timing-framework/worker.js index 23475d9c..66b3016b 100644 --- a/events/features/timing-framework/worker.js +++ b/events/features/timing-framework/worker.js @@ -9,6 +9,7 @@ class TimingWorker { this.channels = new Map(); this.testingManager = new TestingManager(); this.tabId = crypto.randomUUID(); + this.previouslySentItem = null; this.setupMessageHandler(); } @@ -163,14 +164,21 @@ class TimingWorker { async runTimer() { const shouldTrigger = await this.shouldTriggerNextSchedule(this.nextScheduleItem); - const { pathToFragment: currentPath } = this.currentScheduleItem; - const { pathToFragment: nextPath, prev: nextPrev } = this.nextScheduleItem; - - if (shouldTrigger && (nextPath !== currentPath || nextPrev === null)) { - postMessage(this.nextScheduleItem); + let itemToSend = null; + if (shouldTrigger) { + itemToSend = this.nextScheduleItem; this.currentScheduleItem = { ...this.nextScheduleItem }; this.nextScheduleItem = this.nextScheduleItem.next; + } else { + // If no items are triggered and we've reached the end, send the first item as fallback + itemToSend = this.getFirstScheduleItem(); + } + + // Send the item if it's different from what we previously sent + if (itemToSend && itemToSend !== this.previouslySentItem) { + postMessage(itemToSend); + this.previouslySentItem = itemToSend; } if (!this.nextScheduleItem) return; @@ -181,6 +189,15 @@ class TimingWorker { this.timerId = setTimeout(() => this.runTimer(), TimingWorker.getRandomInterval()); } + getFirstScheduleItem() { + // Find the first item in the schedule by traversing backwards from current + let item = this.currentScheduleItem; + while (item?.prev) { + item = item.prev; + } + return item; + } + handleMessage(event) { const { schedule, plugins, testing } = event.data; @@ -200,6 +217,7 @@ class TimingWorker { if (schedule) { this.nextScheduleItem = TimingWorker.getStartScheduleItemByToggleTime(schedule); this.currentScheduleItem = this.nextScheduleItem?.prev || schedule; + this.previouslySentItem = null; } if (!this.nextScheduleItem) return; From cab5a4ea31fbd5460d47b3b2f2489ee4ed0c685e Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Tue, 24 Jun 2025 15:52:30 -0400 Subject: [PATCH 47/93] Webinar Fix WIP --- events/blocks/chrono-box/chrono-box.js | 21 +- .../plugins/metadata/plugin.js | 12 +- .../plugins/mobile-rider/plugin.js | 8 +- events/features/timing-framework/worker.js | 32 +- test-manual.html | 298 ++++++++++++++++++ test-multiple-chronoboxes.html | 258 +++++++++++++++ .../features/timing-framework/worker.test.js | 10 +- 7 files changed, 613 insertions(+), 26 deletions(-) create mode 100644 test-manual.html create mode 100644 test-multiple-chronoboxes.html diff --git a/events/blocks/chrono-box/chrono-box.js b/events/blocks/chrono-box/chrono-box.js index 9663c127..bf0790d0 100644 --- a/events/blocks/chrono-box/chrono-box.js +++ b/events/blocks/chrono-box/chrono-box.js @@ -37,16 +37,19 @@ async function initPlugins(schedule) { const pluginsNeeded = SUPPORTED_PLUGINS.filter((plugin) => schedule.some((item) => item[plugin])); const plugins = await Promise.all(pluginsNeeded.map((plugin) => import(`../../features/timing-framework/plugins/${plugin}/plugin.js`))); + // Generate a unique tabId for this instance + const tabId = crypto.randomUUID(); + const pluginsModules = new Map(); await Promise.all(plugins.map(async (plugin, index) => { const pluginName = pluginsNeeded[index].replace('-', ''); - pluginsModules.set(pluginName, await plugin.init(schedule)); + pluginsModules.set(pluginName, await plugin.default(schedule, tabId)); })); - return pluginsModules; + return { plugins: pluginsModules, tabId }; } -function setScheduleToScheduleWorker(schedule, plugins) { +function setScheduleToScheduleWorker(schedule, plugins, tabId) { const scheduleLinkedList = buildScheduleDoubleLinkedList(schedule); const worker = new Worker('/events/features/timing-framework/worker.js', { type: 'module' }); @@ -59,7 +62,10 @@ function setScheduleToScheduleWorker(schedule, plugins) { const pluginStates = Object.fromEntries( Array.from(plugins.entries()).map(([name, plugin]) => [ name, - Object.fromEntries(plugin), // Convert Map to plain object + { + type: name, + data: plugin.getAll ? plugin.getAll() : plugin, + }, ]), ); @@ -67,6 +73,7 @@ function setScheduleToScheduleWorker(schedule, plugins) { schedule: scheduleLinkedList, plugins: pluginStates, testing, + tabId, }); return worker; @@ -102,7 +109,11 @@ export default async function init(el) { el.innerHTML = ''; const pluginsOutputs = await initPlugins(thisSchedule); - const worker = setScheduleToScheduleWorker(thisSchedule, pluginsOutputs); + const worker = setScheduleToScheduleWorker( + thisSchedule, + pluginsOutputs.plugins, + pluginsOutputs.tabId, + ); worker.onmessage = (event) => { const { pathToFragment } = event.data; diff --git a/events/features/timing-framework/plugins/metadata/plugin.js b/events/features/timing-framework/plugins/metadata/plugin.js index c3fb8dcd..744f1051 100644 --- a/events/features/timing-framework/plugins/metadata/plugin.js +++ b/events/features/timing-framework/plugins/metadata/plugin.js @@ -8,9 +8,9 @@ export const metadataStore = { return store.get(key); }, - set(key, value) { + set(key, value, tabId) { store.set(key, value); - channel.postMessage({ key, value }); + channel.postMessage({ key, value, tabId }); }, getAll() { @@ -18,12 +18,12 @@ export const metadataStore = { }, }; -export default function init(schedule) { +export default function init(schedule, tabId) { const allMetadataInSchedules = schedule.filter((entry) => entry.metadata); - allMetadataInSchedules.forEach((metadata) => { + allMetadataInSchedules.forEach(({ metadata }) => { metadata.forEach((m) => { - const value = parseMetadataPath(metadata.key); - metadataStore.set(m.key, value); + const value = parseMetadataPath(m.key); + metadataStore.set(m.key, value, tabId); }); }); diff --git a/events/features/timing-framework/plugins/mobile-rider/plugin.js b/events/features/timing-framework/plugins/mobile-rider/plugin.js index da8a1141..e3e5c164 100644 --- a/events/features/timing-framework/plugins/mobile-rider/plugin.js +++ b/events/features/timing-framework/plugins/mobile-rider/plugin.js @@ -8,9 +8,9 @@ export const mobileRiderStore = { return store.get(sessionId); }, - set(sessionId, isActive) { + set(sessionId, isActive, tabId) { store.set(sessionId, isActive); - channel.postMessage({ sessionId, isActive }); + channel.postMessage({ sessionId, isActive, tabId }); }, getAll() { @@ -18,7 +18,7 @@ export const mobileRiderStore = { }, }; -export default function init(schedule) { +export default function init(schedule, tabId) { const controller = new MobileRiderController(); const mobileRiderSchedules = schedule.filter((entry) => entry.mobileRider); @@ -26,7 +26,7 @@ export default function init(schedule) { s.mobileRider.forEach((condition) => { const { sessionId } = condition; const isActive = controller.isMediaActive(sessionId); - mobileRiderStore.set(sessionId, isActive); + mobileRiderStore.set(sessionId, isActive, tabId); }); }); diff --git a/events/features/timing-framework/worker.js b/events/features/timing-framework/worker.js index 66b3016b..14435a40 100644 --- a/events/features/timing-framework/worker.js +++ b/events/features/timing-framework/worker.js @@ -2,14 +2,14 @@ import TestingManager from './testing.js'; class TimingWorker { constructor() { - this.currentScheduleItem = null; - this.nextScheduleItem = null; - this.timerId = null; + this.tabId = crypto.randomUUID(); this.plugins = new Map(); this.channels = new Map(); - this.testingManager = new TestingManager(); - this.tabId = crypto.randomUUID(); + this.timerId = null; + this.currentScheduleItem = null; + this.nextScheduleItem = null; this.previouslySentItem = null; + this.testingManager = new TestingManager(); this.setupMessageHandler(); } @@ -147,8 +147,7 @@ class TimingWorker { const isEmpty = !value || (Array.isArray(value) && value.length === 0) || (typeof value === 'object' && Object.keys(value).length === 0); - const isAnyVal = expectedValue.trim().toLowerCase() === 'any' && !isEmpty; - return isAnyVal || value === expectedValue; + return isEmpty || value === expectedValue; } } @@ -199,7 +198,7 @@ class TimingWorker { } handleMessage(event) { - const { schedule, plugins, testing } = event.data; + const { schedule, plugins, testing, tabId } = event.data; if (this.timerId) { clearTimeout(this.timerId); @@ -209,8 +208,23 @@ class TimingWorker { // Initialize testing manager with testing data this.testingManager.init(testing); + // Use the tabId from the message to ensure consistency + if (tabId) { + this.tabId = tabId; + } + if (plugins) { - this.plugins = new Map(Object.entries(plugins)); + // Recreate store interfaces from the data + const pluginStores = new Map(); + Object.entries(plugins).forEach(([name, pluginInfo]) => { + const store = new Map(Object.entries(pluginInfo.data)); + pluginStores.set(name, { + get: (key) => store.get(key), + set: (key, value) => store.set(key, value), + getAll: () => Object.fromEntries(store), + }); + }); + this.plugins = pluginStores; this.setupBroadcastChannels(this.plugins); } diff --git a/test-manual.html b/test-manual.html new file mode 100644 index 00000000..423a12fb --- /dev/null +++ b/test-manual.html @@ -0,0 +1,298 @@ + + + + + + Timing Framework Manual Test + + + +

Timing Framework Manual Test

+ +
+

Test Overview

+

This page tests the timing framework with multiple chrono-boxes, plugin stores, and worker communication.

+

Use the buttons below to run different test scenarios.

+
+ +
+

Test Controls

+ + + + + +
+ +
+ + +
+

Chrono-Box 1

+
+
+ +
+

Chrono-Box 2

+
+
+ + + + diff --git a/test-multiple-chronoboxes.html b/test-multiple-chronoboxes.html new file mode 100644 index 00000000..94ca4ff5 --- /dev/null +++ b/test-multiple-chronoboxes.html @@ -0,0 +1,258 @@ + + + + + + Multiple Chrono-Boxes Test + + + +

Multiple Chrono-Boxes Test

+ +
+

Test Overview

+

This page tests multiple chrono-boxes with separate plugin stores and worker communication.

+

Each chrono-box should maintain its own isolated state.

+
+ +
+

Test Controls

+ + + +
+ +
+ + +
+

Chrono-Box 1

+
+
+ +
+

Chrono-Box 2

+
+
+ + + + diff --git a/test/unit/features/timing-framework/worker.test.js b/test/unit/features/timing-framework/worker.test.js index b02f268a..6770febf 100644 --- a/test/unit/features/timing-framework/worker.test.js +++ b/test/unit/features/timing-framework/worker.test.js @@ -124,8 +124,14 @@ describe('TimingWorker', () => { describe('handleMessage', () => { it('should set up plugins and channels', () => { const plugins = { - metadata: { key1: 'value1' }, - mobileRider: { session1: true }, + metadata: { + type: 'metadata', + data: { key1: 'value1' }, + }, + mobileRider: { + type: 'mobileRider', + data: { session1: true }, + }, }; worker.handleMessage({ From 87d36c6c7687b7f45e1ad93c831b0669430a29d5 Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Tue, 24 Jun 2025 16:27:39 -0400 Subject: [PATCH 48/93] Fix metadata array issue --- events/features/timing-framework/worker.js | 20 ++++--- .../features/timing-framework/worker.test.js | 56 ++++++++++++++++++- 2 files changed, 67 insertions(+), 9 deletions(-) diff --git a/events/features/timing-framework/worker.js b/events/features/timing-framework/worker.js index 14435a40..c277e5b5 100644 --- a/events/features/timing-framework/worker.js +++ b/events/features/timing-framework/worker.js @@ -138,16 +138,20 @@ class TimingWorker { } // Check metadata conditions if present - if (scheduleItem.metadata) { + if (scheduleItem.metadata && Array.isArray(scheduleItem.metadata)) { const metadataStore = this.plugins.get('metadata'); if (metadataStore) { - const { key, expectedValue } = scheduleItem.metadata; - const value = metadataStore.get(key); - - const isEmpty = !value - || (Array.isArray(value) && value.length === 0) - || (typeof value === 'object' && Object.keys(value).length === 0); - return isEmpty || value === expectedValue; + // Require all metadata conditions to be met + const allConditionMet = scheduleItem.metadata.every(({ key, expectedValue }) => { + const value = metadataStore.get(key); + const isEmpty = !value + || (Array.isArray(value) && value.length === 0) + || (typeof value === 'object' && Object.keys(value).length === 0); + const isAnyVal = !expectedValue && !isEmpty; + const matchesExpectedValue = expectedValue && value === expectedValue; + return isAnyVal || matchesExpectedValue; + }); + return allConditionMet; } } diff --git a/test/unit/features/timing-framework/worker.test.js b/test/unit/features/timing-framework/worker.test.js index 6770febf..403fcb5c 100644 --- a/test/unit/features/timing-framework/worker.test.js +++ b/test/unit/features/timing-framework/worker.test.js @@ -99,7 +99,7 @@ describe('TimingWorker', () => { it('should handle metadata conditions', async () => { const nextItem = { - metadata: { key: 'testKey', expectedValue: 'expected' }, + metadata: [{ key: 'testKey', expectedValue: 'expected' }], pathToFragment: '/next', }; @@ -109,6 +109,60 @@ describe('TimingWorker', () => { expect(result).to.be.true; }); + it('should handle multiple metadata conditions', async () => { + const nextItem = { + metadata: [ + { key: 'testKey1', expectedValue: 'expected1' }, + { key: 'testKey2', expectedValue: 'expected2' }, + ], + pathToFragment: '/next', + }; + + worker.plugins.set('metadata', new Map([ + ['testKey1', 'wrong'], + ['testKey2', 'expected2'], + ])); + + const result = await worker.shouldTriggerNextSchedule(nextItem); + expect(result).to.be.false; + }); + + it('should trigger when all metadata conditions are met', async () => { + const nextItem = { + metadata: [ + { key: 'testKey1', expectedValue: 'expected1' }, + { key: 'testKey2', expectedValue: 'expected2' }, + ], + pathToFragment: '/next', + }; + + worker.plugins.set('metadata', new Map([ + ['testKey1', 'expected1'], + ['testKey2', 'expected2'], + ])); + + const result = await worker.shouldTriggerNextSchedule(nextItem); + expect(result).to.be.true; + }); + + it('should not trigger when no metadata conditions are met', async () => { + const nextItem = { + metadata: [ + { key: 'testKey1', expectedValue: 'expected1' }, + { key: 'testKey2', expectedValue: 'expected2' }, + ], + pathToFragment: '/next', + }; + + worker.plugins.set('metadata', new Map([ + ['testKey1', 'wrong1'], + ['testKey2', 'wrong2'], + ])); + + const result = await worker.shouldTriggerNextSchedule(nextItem); + expect(result).to.be.false; + }); + it('should fall back to toggleTime if no plugins are blocking', async () => { const now = Date.now(); const nextItem = { From 938f4354333173229baa87e80850a2c453bf2b4f Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Wed, 25 Jun 2025 10:04:12 -0400 Subject: [PATCH 49/93] Added more error handling and added potential multiple MR ID handling --- events/blocks/chrono-box/chrono-box.js | 12 ++++ .../plugins/mobile-rider/plugin.js | 16 ++++- events/features/timing-framework/testing.js | 18 +++++- events/features/timing-framework/worker.js | 62 ++++++++++++------- 4 files changed, 79 insertions(+), 29 deletions(-) diff --git a/events/blocks/chrono-box/chrono-box.js b/events/blocks/chrono-box/chrono-box.js index 760b8359..836947da 100644 --- a/events/blocks/chrono-box/chrono-box.js +++ b/events/blocks/chrono-box/chrono-box.js @@ -134,6 +134,18 @@ export default async function init(el) { spTheme.remove(); el.removeAttribute('style'); el.classList.remove('loading'); + }).catch((error) => { + // Handle fragment loading errors + window.lana?.log(`Error loading fragment ${pathToFragment}: ${JSON.stringify(error)}`); + + // Remove loading state + spTheme.remove(); + el.removeAttribute('style'); + el.classList.remove('loading'); + + // Show error state to user + el.innerHTML = '
Unable to load content. Please refresh the page.
'; + el.classList.add('error'); }); }; } diff --git a/events/features/timing-framework/plugins/mobile-rider/plugin.js b/events/features/timing-framework/plugins/mobile-rider/plugin.js index e3e5c164..538d3269 100644 --- a/events/features/timing-framework/plugins/mobile-rider/plugin.js +++ b/events/features/timing-framework/plugins/mobile-rider/plugin.js @@ -23,11 +23,21 @@ export default function init(schedule, tabId) { const mobileRiderSchedules = schedule.filter((entry) => entry.mobileRider); mobileRiderSchedules.forEach((s) => { - s.mobileRider.forEach((condition) => { - const { sessionId } = condition; + // Handle mobileRider as an object with sessionId property + if (s.mobileRider && typeof s.mobileRider === 'object' && s.mobileRider.sessionId) { + const { sessionId } = s.mobileRider; const isActive = controller.isMediaActive(sessionId); mobileRiderStore.set(sessionId, isActive, tabId); - }); + } else if (Array.isArray(s.mobileRider)) { + // Backward compatibility for array format + s.mobileRider.forEach((condition) => { + if (condition && condition.sessionId) { + const { sessionId } = condition; + const isActive = controller.isMediaActive(sessionId); + mobileRiderStore.set(sessionId, isActive, tabId); + } + }); + } }); return mobileRiderStore; diff --git a/events/features/timing-framework/testing.js b/events/features/timing-framework/testing.js index 4185a16f..c46391d2 100644 --- a/events/features/timing-framework/testing.js +++ b/events/features/timing-framework/testing.js @@ -6,9 +6,21 @@ export default class TestingManager { init(testingData) { if (testingData?.toggleTime) { - this.isTestMode = true; - const currentTime = new Date().getTime(); - this.timeOffset = testingData.toggleTime - currentTime; + const toggleTime = parseInt(testingData.toggleTime, 10); + + // Validate that toggleTime is a valid number + if (!Number.isNaN(toggleTime) && Number.isFinite(toggleTime)) { + this.isTestMode = true; + const currentTime = new Date().getTime(); + this.timeOffset = toggleTime - currentTime; + } else { + window.lana?.log(`Invalid toggleTime provided for testing: ${testingData.toggleTime}`); + this.isTestMode = false; + this.timeOffset = 0; + } + } else { + this.isTestMode = false; + this.timeOffset = 0; } } diff --git a/events/features/timing-framework/worker.js b/events/features/timing-framework/worker.js index c277e5b5..fcd80c8b 100644 --- a/events/features/timing-framework/worker.js +++ b/events/features/timing-framework/worker.js @@ -15,38 +15,54 @@ class TimingWorker { setupBroadcastChannels(plugins) { // Close any existing channels - this.channels.forEach((channel) => channel.close()); + this.channels.forEach((channel) => { + try { + if (channel && typeof channel.close === 'function') { + channel.close(); + } + } catch (error) { + window.lana?.log(`Error closing BroadcastChannel: ${JSON.stringify(error)}`); + } + }); this.channels.clear(); // Only set up channels for enabled plugins if (plugins.has('metadata')) { - const channel = new BroadcastChannel('metadata-store'); - channel.onmessage = (event) => { - const { tabId, key, value } = event.data; - // Only process messages from this tab - if (tabId === this.tabId) { - const metadataStore = this.plugins.get('metadata'); - if (metadataStore) { - metadataStore.set(key, value); + try { + const channel = new BroadcastChannel('metadata-store'); + channel.onmessage = (event) => { + const { tabId, key, value } = event.data; + // Only process messages from this tab + if (tabId === this.tabId) { + const metadataStore = this.plugins.get('metadata'); + if (metadataStore) { + metadataStore.set(key, value); + } } - } - }; - this.channels.set('metadata', channel); + }; + this.channels.set('metadata', channel); + } catch (error) { + window.lana?.log(`Error setting up metadata BroadcastChannel: ${JSON.stringify(error)}`); + } } if (plugins.has('mobileRider')) { - const channel = new BroadcastChannel('mobile-rider-store'); - channel.onmessage = (event) => { - const { tabId, sessionId, isActive } = event.data; - // Only process messages from this tab - if (tabId === this.tabId) { - const mobileRiderStore = this.plugins.get('mobileRider'); - if (mobileRiderStore) { - mobileRiderStore.set(sessionId, isActive); + try { + const channel = new BroadcastChannel('mobile-rider-store'); + channel.onmessage = (event) => { + const { tabId, sessionId, isActive } = event.data; + // Only process messages from this tab + if (tabId === this.tabId) { + const mobileRiderStore = this.plugins.get('mobileRider'); + if (mobileRiderStore) { + mobileRiderStore.set(sessionId, isActive); + } } - } - }; - this.channels.set('mobileRider', channel); + }; + this.channels.set('mobileRider', channel); + } catch (error) { + window.lana?.log(`Error setting up mobileRider BroadcastChannel: ${JSON.stringify(error)}`); + } } } From f1973568e9bfebf19e3d0f942c9ea3fa11a8df66 Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Wed, 25 Jun 2025 10:06:28 -0400 Subject: [PATCH 50/93] linting --- events/features/timing-framework/testing.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/events/features/timing-framework/testing.js b/events/features/timing-framework/testing.js index c46391d2..c996d37c 100644 --- a/events/features/timing-framework/testing.js +++ b/events/features/timing-framework/testing.js @@ -7,7 +7,7 @@ export default class TestingManager { init(testingData) { if (testingData?.toggleTime) { const toggleTime = parseInt(testingData.toggleTime, 10); - + // Validate that toggleTime is a valid number if (!Number.isNaN(toggleTime) && Number.isFinite(toggleTime)) { this.isTestMode = true; From f6ddf4950609658b73b38f2cca048753315d738d Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Wed, 25 Jun 2025 10:08:08 -0400 Subject: [PATCH 51/93] more linting --- events/blocks/chrono-box/chrono-box.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/events/blocks/chrono-box/chrono-box.js b/events/blocks/chrono-box/chrono-box.js index 836947da..22b6205f 100644 --- a/events/blocks/chrono-box/chrono-box.js +++ b/events/blocks/chrono-box/chrono-box.js @@ -1,4 +1,4 @@ -import { readBlockConfig, LIBS, getMetadata, parseMetadataPath } from '../../scripts/utils.js'; +import { readBlockConfig, LIBS, getMetadata } from '../../scripts/utils.js'; function buildScheduleDoubleLinkedList(entries) { if (!entries.length) return null; From dfa7020f982799c4f00fbbb8bd082b41aaa45b6d Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Wed, 9 Jul 2025 15:00:37 +0530 Subject: [PATCH 52/93] Override form id via url --- rs/360-KCI-804/images/mktoTestFormConfig.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rs/360-KCI-804/images/mktoTestFormConfig.js b/rs/360-KCI-804/images/mktoTestFormConfig.js index 6905a6ac..1e994580 100644 --- a/rs/360-KCI-804/images/mktoTestFormConfig.js +++ b/rs/360-KCI-804/images/mktoTestFormConfig.js @@ -49,6 +49,12 @@ if (typeof mkto_testing_loader != "function" && typeof mkto_testing_loader == "u const MUNCHKIN_ID = "360-KCI-804"; let formID = 3131; + const urlParams = new URLSearchParams(window.location.search); + if (urlParams.has('formId')) { + formID = urlParams.get('formId'); + } + console.log('formID', formID); + let resourceFormHTML = `
From 1d4f8fe17e7e55d8cf08eb5cfb4b7406b1e1621c Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Wed, 9 Jul 2025 11:48:07 -0400 Subject: [PATCH 53/93] self-supply tabId from sessionStorage --- events/blocks/chrono-box/chrono-box.js | 12 ++- events/features/timing-framework/README.md | 102 ++++++++++++++++-- .../plugins/metadata/plugin.js | 8 +- .../plugins/mobile-rider/plugin.js | 10 +- events/features/timing-framework/worker.js | 23 +++- test-multiple-chronoboxes.html | 65 +++++------ .../features/timing-framework/worker.test.js | 41 +++++-- 7 files changed, 196 insertions(+), 65 deletions(-) diff --git a/events/blocks/chrono-box/chrono-box.js b/events/blocks/chrono-box/chrono-box.js index 22b6205f..ff402c9a 100644 --- a/events/blocks/chrono-box/chrono-box.js +++ b/events/blocks/chrono-box/chrono-box.js @@ -37,13 +37,19 @@ async function initPlugins(schedule) { const pluginsNeeded = SUPPORTED_PLUGINS.filter((plugin) => schedule.some((item) => item[plugin])); const plugins = await Promise.all(pluginsNeeded.map((plugin) => import(`../../features/timing-framework/plugins/${plugin}/plugin.js`))); - // Generate a unique tabId for this instance - const tabId = crypto.randomUUID(); + // Get or create a global tabId that's shared across all chrono-boxes on this page + // This ensures that multiple chrono-boxes on the same page use the same tabId, + // allowing their plugin stores to communicate via BroadcastChannel correctly + let tabId = sessionStorage.getItem('chrono-box-tab-id'); + if (!tabId) { + tabId = crypto.randomUUID(); + sessionStorage.setItem('chrono-box-tab-id', tabId); + } const pluginsModules = new Map(); await Promise.all(plugins.map(async (plugin, index) => { const pluginName = pluginsNeeded[index].replace('-', ''); - pluginsModules.set(pluginName, await plugin.default(schedule, tabId)); + pluginsModules.set(pluginName, await plugin.default(schedule)); })); return { plugins: pluginsModules, tabId }; diff --git a/events/features/timing-framework/README.md b/events/features/timing-framework/README.md index 3e437fca..03eac0be 100644 --- a/events/features/timing-framework/README.md +++ b/events/features/timing-framework/README.md @@ -9,6 +9,7 @@ The Timing Framework is a robust system for managing dynamic content scheduling 1. **Chronobox Block** - Entry point for the timing system - Loads schedule from metadata or static configuration + - Generates and manages global tabId via sessionStorage - Dynamically imports and initializes required plugins - Creates and manages the Timing Worker - Handles fragment loading with loading states @@ -27,6 +28,7 @@ The Timing Framework is a robust system for managing dynamic content scheduling - Metadata Plugin: Handles metadata-based conditions - Plugins communicate via BroadcastChannel - Each plugin maintains its own state store + - Plugins use `getCurrentTabId()` API for unified state management ### Data Flow @@ -312,13 +314,27 @@ Benefits: - **Cross-context**: Works across different windows, tabs, and iframes - **State Management**: Centralized state management for plugins -#### Tab Isolation -The framework implements tab isolation to prevent cross-tab interference: -- Each tab instance generates a unique UUID on initialization +#### Tab Isolation and Unification +The framework implements a sophisticated tab management system that provides both isolation and unification: + +**Tab Isolation (Cross-Tab)** +- Each browser tab generates a unique UUID stored in sessionStorage - All BroadcastChannel messages include the sender's tab ID - Messages are only processed if they originate from the same tab - This prevents schedule transitions in one tab from affecting others +**Tab Unification (Within Tab)** +- Multiple chrono-boxes on the same page share the same tabId via sessionStorage +- All plugin stores within a tab are unified and communicate via BroadcastChannel +- This ensures consistent state across all chrono-boxes on the same page + +**Implementation Details** +- TabId is generated once per page session and stored in `sessionStorage.getItem('chrono-box-tab-id')` +- Plugins automatically retrieve the tabId via `getCurrentTabId()` API (reads from sessionStorage) +- Worker receives the tabId from the chrono-box and stores it in `this.tabId` for message filtering +- The self-supplied approach eliminates the need for manual tabId parameter passing +- Both worker and plugins use the same tabId source (sessionStorage for plugins, this.tabId for worker) + Example message format: ```javascript { @@ -328,52 +344,116 @@ Example message format: } ``` -This isolation ensures: -- Independent testing in different tabs -- No interference between multiple event pages -- Clean separation of plugin states -- Predictable behavior in each tab +This system ensures: +- **Cross-tab isolation**: Independent testing in different tabs +- **Within-tab unification**: Multiple chrono-boxes share plugin state +- **No interference**: Clean separation between different browser tabs +- **Predictable behavior**: Consistent state management within each tab ### Implementation Example ```javascript +// Chrono-box initialization with tabId management +let tabId = sessionStorage.getItem('chrono-box-tab-id'); +if (!tabId) { + tabId = crypto.randomUUID(); + sessionStorage.setItem('chrono-box-tab-id', tabId); +} + // Worker setup const worker = new Worker('/events/features/timing-framework/worker.js'); // Plugin communication via BroadcastChannel const channel = new BroadcastChannel('metadata-store'); channel.onmessage = (event) => { - const { key, value } = event.data; - // Handle plugin state updates + const { tabId: messageTabId, key, value } = event.data; + // Only process messages from the same tab + if (messageTabId === tabId) { + // Handle plugin state updates + } }; // Worker communication worker.postMessage({ - message: 'schedule', schedule: scheduleLinkedList, plugins: pluginStates, testing, + tabId, // Pass the unified tabId to the worker }); ``` +### Plugin Development + +When creating new plugins, the tabId is automatically handled internally: + +```javascript +import { getCurrentTabId } from '../../worker.js'; + +export const yourPluginStore = { + get(key) { + return store.get(key); + }, + + set(key, value) { + const tabId = getCurrentTabId(); // Automatically retrieved from sessionStorage + store.set(key, value); + channel.postMessage({ key, value, tabId }); + }, + + getAll() { + return Object.fromEntries(store); + }, +}; + +export default function init(schedule) { + // Your plugin logic here + // No need to manually handle tabId - it's self-supplied + + return yourPluginStore; +} +``` + +**Architecture Notes:** +- **Plugins**: Run in main thread, use `getCurrentTabId()` to read from sessionStorage +- **Worker**: Runs in separate thread, uses `this.tabId` (received from chrono-box) +- **Consistency**: Both use the same tabId value, just accessed differently based on context + +**Benefits of the self-supplied approach:** +- **Simplified API**: Plugins don't need to pass tabId parameters +- **Automatic Management**: tabId is retrieved when needed +- **Encapsulation**: Hides implementation details from plugins +- **Error Handling**: Centralized error handling for missing tabId +- **Testing**: Easy to mock in unit tests +- **Flexibility**: Can change implementation without updating plugins + ### Why This Architecture? 1. **Separation of Concerns** - Schedule processing is isolated in the worker - UI updates happen on the main thread - Plugin state is managed via BroadcastChannel + - TabId management is centralized via sessionStorage 2. **Performance Optimization** - Main thread stays responsive - Schedule processing is non-blocking - Real-time updates are efficient + - Single tabId generation per page session 3. **Scalability** - Can handle complex schedules - Supports multiple plugin types - Maintains performance under load + - Supports multiple chrono-boxes on the same page 4. **Reliability** - Consistent timing checks - Reliable state management - Robust error handling + - Unified plugin state across chrono-boxes + +5. **Tab Management** + - **Cross-tab isolation**: Each browser tab operates independently + - **Within-tab unification**: Multiple chrono-boxes share plugin state + - **Session persistence**: TabId persists across page refreshes + - **Clean separation**: No interference between different tabs diff --git a/events/features/timing-framework/plugins/metadata/plugin.js b/events/features/timing-framework/plugins/metadata/plugin.js index 744f1051..1e1a57dc 100644 --- a/events/features/timing-framework/plugins/metadata/plugin.js +++ b/events/features/timing-framework/plugins/metadata/plugin.js @@ -1,4 +1,5 @@ import { parseMetadataPath } from '../../../../scripts/utils.js'; +import { getCurrentTabId } from '../../worker.js'; const store = new Map(); const channel = new BroadcastChannel('metadata-store'); @@ -8,7 +9,8 @@ export const metadataStore = { return store.get(key); }, - set(key, value, tabId) { + set(key, value) { + const tabId = getCurrentTabId(); store.set(key, value); channel.postMessage({ key, value, tabId }); }, @@ -18,12 +20,12 @@ export const metadataStore = { }, }; -export default function init(schedule, tabId) { +export default function init(schedule) { const allMetadataInSchedules = schedule.filter((entry) => entry.metadata); allMetadataInSchedules.forEach(({ metadata }) => { metadata.forEach((m) => { const value = parseMetadataPath(m.key); - metadataStore.set(m.key, value, tabId); + metadataStore.set(m.key, value); }); }); diff --git a/events/features/timing-framework/plugins/mobile-rider/plugin.js b/events/features/timing-framework/plugins/mobile-rider/plugin.js index 538d3269..547a6cfd 100644 --- a/events/features/timing-framework/plugins/mobile-rider/plugin.js +++ b/events/features/timing-framework/plugins/mobile-rider/plugin.js @@ -1,4 +1,5 @@ import MobileRiderController from './mobile-rider-controller.js'; +import { getCurrentTabId } from '../../worker.js'; const store = new Map(); const channel = new BroadcastChannel('mobile-rider-store'); @@ -8,7 +9,8 @@ export const mobileRiderStore = { return store.get(sessionId); }, - set(sessionId, isActive, tabId) { + set(sessionId, isActive) { + const tabId = getCurrentTabId(); store.set(sessionId, isActive); channel.postMessage({ sessionId, isActive, tabId }); }, @@ -18,7 +20,7 @@ export const mobileRiderStore = { }, }; -export default function init(schedule, tabId) { +export default function init(schedule) { const controller = new MobileRiderController(); const mobileRiderSchedules = schedule.filter((entry) => entry.mobileRider); @@ -27,14 +29,14 @@ export default function init(schedule, tabId) { if (s.mobileRider && typeof s.mobileRider === 'object' && s.mobileRider.sessionId) { const { sessionId } = s.mobileRider; const isActive = controller.isMediaActive(sessionId); - mobileRiderStore.set(sessionId, isActive, tabId); + mobileRiderStore.set(sessionId, isActive); } else if (Array.isArray(s.mobileRider)) { // Backward compatibility for array format s.mobileRider.forEach((condition) => { if (condition && condition.sessionId) { const { sessionId } = condition; const isActive = controller.isMediaActive(sessionId); - mobileRiderStore.set(sessionId, isActive, tabId); + mobileRiderStore.set(sessionId, isActive); } }); } diff --git a/events/features/timing-framework/worker.js b/events/features/timing-framework/worker.js index fcd80c8b..674aa729 100644 --- a/events/features/timing-framework/worker.js +++ b/events/features/timing-framework/worker.js @@ -1,8 +1,22 @@ import TestingManager from './testing.js'; +/** + * Gets the current tabId from sessionStorage + * This function is used by plugins that are not part of the worker context + * @returns {string} The current tabId + * @throws {Error} If tabId is not found in sessionStorage + */ +export function getCurrentTabId() { + const tabId = sessionStorage.getItem('chrono-box-tab-id'); + if (!tabId) { + throw new Error('tabId not found in sessionStorage. Ensure chrono-box is initialized first.'); + } + return tabId; +} + class TimingWorker { constructor() { - this.tabId = crypto.randomUUID(); + this.tabId = null; this.plugins = new Map(); this.channels = new Map(); this.timerId = null; @@ -228,10 +242,11 @@ class TimingWorker { // Initialize testing manager with testing data this.testingManager.init(testing); - // Use the tabId from the message to ensure consistency - if (tabId) { - this.tabId = tabId; + // Set the tabId from the message (required for plugin communication) + if (!tabId) { + throw new Error('tabId is required for worker initialization'); } + this.tabId = tabId; if (plugins) { // Recreate store interfaces from the data diff --git a/test-multiple-chronoboxes.html b/test-multiple-chronoboxes.html index 94ca4ff5..0df1575f 100644 --- a/test-multiple-chronoboxes.html +++ b/test-multiple-chronoboxes.html @@ -61,13 +61,13 @@

Multiple Chrono-Boxes Test

Test Overview

-

This page tests multiple chrono-boxes with separate plugin stores and worker communication.

-

Each chrono-box should maintain its own isolated state.

+

This page tests multiple chrono-boxes with unified plugin stores and worker communication.

+

All chrono-boxes on the same page should share the same tabId and communicate via BroadcastChannel.

Test Controls

- +
@@ -128,7 +128,7 @@

Chrono-Box 2

// Test functions window.runIsolationTest = async () => { const results = document.getElementById('test-results'); - results.innerHTML = '

Running Isolation Test...

'; + results.innerHTML = '

Running Unified Tab Test...

'; try { // Test 1: Import plugins @@ -137,7 +137,7 @@

Chrono-Box 2

results.innerHTML += `

✅ Plugins imported successfully

`; - // Test 2: Create separate stores + // Test 2: Create separate stores with shared tabId const schedule1 = [ { metadata: [{ key: 'video.url' }], @@ -151,47 +151,48 @@

Chrono-Box 2

} ]; - const tabId1 = window.crypto.randomUUID(); - const tabId2 = window.crypto.randomUUID(); + // Clear any existing tabId to start fresh + sessionStorage.removeItem('chrono-box-tab-id'); - const metadataStore1 = metadataPlugin(schedule1, tabId1); - const metadataStore2 = metadataPlugin(schedule2, tabId2); - const mobileRiderStore1 = mobileRiderPlugin(schedule1, tabId1); - const mobileRiderStore2 = mobileRiderPlugin(schedule2, tabId2); + const metadataStore1 = metadataPlugin(schedule1); + const metadataStore2 = metadataPlugin(schedule2); + const mobileRiderStore1 = mobileRiderPlugin(schedule1); + const mobileRiderStore2 = mobileRiderPlugin(schedule2); - results.innerHTML += `

✅ Created separate store instances

`; + results.innerHTML += `

✅ Created store instances

`; - // Test 3: Verify store isolation - metadataStore1.set('test.key', 'value-1', tabId1); - metadataStore2.set('test.key', 'value-2', tabId2); - - const value1 = metadataStore1.get('test.key'); - const value2 = metadataStore2.get('test.key'); - - if (value1 === 'value-1' && value2 === 'value-2') { - results.innerHTML += `

✅ Store isolation verified - stores maintain separate data

`; + // Test 3: Verify stores share the same tabId + const tabId1 = sessionStorage.getItem('chrono-box-tab-id'); + if (tabId1) { + results.innerHTML += `

✅ Tab ID created and stored: ${tabId1}

`; } else { - results.innerHTML += `

❌ Store isolation failed - data is shared between stores

`; + results.innerHTML += `

❌ Tab ID not found in sessionStorage

`; } - // Test 4: Verify different tab IDs - if (tabId1 !== tabId2) { - results.innerHTML += `

✅ Tab isolation verified - different tab IDs generated

`; + // Test 4: Verify stores can communicate via BroadcastChannel + metadataStore1.set('shared.key', 'value-from-store1'); + const valueFromStore2 = metadataStore2.get('shared.key'); + + if (valueFromStore2 === 'value-from-store1') { + results.innerHTML += `

✅ Store communication verified - stores share data via BroadcastChannel

`; } else { - results.innerHTML += `

❌ Tab isolation failed - same tab ID generated

`; + results.innerHTML += `

❌ Store communication failed - stores are not sharing data

`; } - // Test 5: Verify separate BroadcastChannels - if (metadataStore1._channel !== metadataStore2._channel) { - results.innerHTML += `

✅ BroadcastChannel isolation verified - separate channels created

`; + // Test 5: Verify mobile rider stores also share data + mobileRiderStore1.set('shared-session', true); + const sessionFromStore2 = mobileRiderStore2.get('shared-session'); + + if (sessionFromStore2 === true) { + results.innerHTML += `

✅ Mobile rider store communication verified

`; } else { - results.innerHTML += `

❌ BroadcastChannel isolation failed - same channel shared

`; + results.innerHTML += `

❌ Mobile rider store communication failed

`; } - results.innerHTML += `

✅ Isolation Test Passed

`; + results.innerHTML += `

✅ Unified Tab Test Passed

`; } catch (error) { - results.innerHTML += `

❌ Isolation Test Failed

${error.message}

`; + results.innerHTML += `

❌ Unified Tab Test Failed

${error.message}

`; } }; diff --git a/test/unit/features/timing-framework/worker.test.js b/test/unit/features/timing-framework/worker.test.js index 403fcb5c..a4a1079d 100644 --- a/test/unit/features/timing-framework/worker.test.js +++ b/test/unit/features/timing-framework/worker.test.js @@ -190,6 +190,7 @@ describe('TimingWorker', () => { worker.handleMessage({ data: { + tabId: 'test-tab-id', plugins, schedule: { toggleTime: Date.now() }, }, @@ -250,11 +251,23 @@ describe('TimingWorker', () => { describe('BroadcastChannel handling', () => { it('should only process messages from the same tab', () => { const metadataWorker = new TimingWorker(); - const metadataStore = new Map(); - metadataWorker.plugins.set('metadata', metadataStore); - // Set up the channel - metadataWorker.setupBroadcastChannels(new Set(['metadata'])); + // Initialize the worker with a tabId and plugins + metadataWorker.handleMessage({ + data: { + tabId: 'test-tab-id', + plugins: { + metadata: { + type: 'metadata', + data: {}, + }, + }, + schedule: { toggleTime: Date.now() }, + }, + }); + + // Get the store from the worker's plugins + const metadataStore = metadataWorker.plugins.get('metadata'); const channel = metadataWorker.channels.get('metadata'); // Send message from different tab @@ -280,11 +293,23 @@ describe('TimingWorker', () => { it('should handle mobile rider messages with tab isolation', () => { const riderWorker = new TimingWorker(); - const mobileRiderStore = new Map(); - riderWorker.plugins.set('mobileRider', mobileRiderStore); - // Set up the channel - riderWorker.setupBroadcastChannels(new Set(['mobileRider'])); + // Initialize the worker with a tabId and plugins + riderWorker.handleMessage({ + data: { + tabId: 'test-tab-id', + plugins: { + mobileRider: { + type: 'mobileRider', + data: {}, + }, + }, + schedule: { toggleTime: Date.now() }, + }, + }); + + // Get the store from the worker's plugins + const mobileRiderStore = riderWorker.plugins.get('mobileRider'); const channel = riderWorker.channels.get('mobileRider'); // Send message from different tab From d1d120460e2eb1f380121c4b9fcbdda32c38fbd1 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Mon, 21 Jul 2025 17:07:59 +0530 Subject: [PATCH 54/93] auto promote to next view in chrono box --- events/blocks/chrono-box/chrono-box.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/events/blocks/chrono-box/chrono-box.js b/events/blocks/chrono-box/chrono-box.js index ff402c9a..2fd46324 100644 --- a/events/blocks/chrono-box/chrono-box.js +++ b/events/blocks/chrono-box/chrono-box.js @@ -1,3 +1,4 @@ +import { metadataStore } from '../../features/timing-framework/plugins/metadata/plugin.js'; import { readBlockConfig, LIBS, getMetadata } from '../../scripts/utils.js'; function buildScheduleDoubleLinkedList(entries) { @@ -154,4 +155,9 @@ export default async function init(el) { el.classList.add('error'); }); }; + + setTimeout(() => { + console.log('setting video'); + metadataStore.set('video', 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'); + }, 10000); } From 8c1e9d2063fb3d0475b12c7eb7556700e81792f5 Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Mon, 21 Jul 2025 12:01:40 -0400 Subject: [PATCH 55/93] Fixing tabId import location --- events/blocks/chrono-box/chrono-box.js | 21 ++++++++++++++++--- events/features/timing-framework/README.md | 2 +- .../plugins/metadata/plugin.js | 3 +-- .../plugins/mobile-rider/plugin.js | 2 +- events/features/timing-framework/worker.js | 15 +------------ events/scripts/utils.js | 8 +++++++ 6 files changed, 30 insertions(+), 21 deletions(-) diff --git a/events/blocks/chrono-box/chrono-box.js b/events/blocks/chrono-box/chrono-box.js index ff402c9a..df5fee9d 100644 --- a/events/blocks/chrono-box/chrono-box.js +++ b/events/blocks/chrono-box/chrono-box.js @@ -57,7 +57,15 @@ async function initPlugins(schedule) { function setScheduleToScheduleWorker(schedule, plugins, tabId) { const scheduleLinkedList = buildScheduleDoubleLinkedList(schedule); - const worker = new Worker('/events/features/timing-framework/worker.js', { type: 'module' }); + + // Add error handling for worker creation + let worker; + try { + worker = new Worker('/events/features/timing-framework/worker.js', { type: 'module' }); + } catch (error) { + window.lana?.log(`Error creating worker: ${JSON.stringify(error)}`); + throw error; + } // Get testing data from URL params const params = new URLSearchParams(document.location.search); @@ -75,12 +83,19 @@ function setScheduleToScheduleWorker(schedule, plugins, tabId) { ]), ); - worker.postMessage({ + const messageData = { schedule: scheduleLinkedList, plugins: pluginStates, testing, tabId, - }); + }; + + try { + worker.postMessage(messageData); + } catch (error) { + window.lana?.log(`Error posting message to worker: ${JSON.stringify(error)}`); + throw error; + } return worker; } diff --git a/events/features/timing-framework/README.md b/events/features/timing-framework/README.md index 03eac0be..7dc6c2d3 100644 --- a/events/features/timing-framework/README.md +++ b/events/features/timing-framework/README.md @@ -387,7 +387,7 @@ worker.postMessage({ When creating new plugins, the tabId is automatically handled internally: ```javascript -import { getCurrentTabId } from '../../worker.js'; +import { getCurrentTabId } from '../../../../scripts/utils.js'; export const yourPluginStore = { get(key) { diff --git a/events/features/timing-framework/plugins/metadata/plugin.js b/events/features/timing-framework/plugins/metadata/plugin.js index 1e1a57dc..7b7b5c75 100644 --- a/events/features/timing-framework/plugins/metadata/plugin.js +++ b/events/features/timing-framework/plugins/metadata/plugin.js @@ -1,5 +1,4 @@ -import { parseMetadataPath } from '../../../../scripts/utils.js'; -import { getCurrentTabId } from '../../worker.js'; +import { parseMetadataPath, getCurrentTabId } from '../../../../scripts/utils.js'; const store = new Map(); const channel = new BroadcastChannel('metadata-store'); diff --git a/events/features/timing-framework/plugins/mobile-rider/plugin.js b/events/features/timing-framework/plugins/mobile-rider/plugin.js index 547a6cfd..0691f9e0 100644 --- a/events/features/timing-framework/plugins/mobile-rider/plugin.js +++ b/events/features/timing-framework/plugins/mobile-rider/plugin.js @@ -1,5 +1,5 @@ import MobileRiderController from './mobile-rider-controller.js'; -import { getCurrentTabId } from '../../worker.js'; +import { getCurrentTabId } from '../../../../scripts/utils.js'; const store = new Map(); const channel = new BroadcastChannel('mobile-rider-store'); diff --git a/events/features/timing-framework/worker.js b/events/features/timing-framework/worker.js index 674aa729..45aad6ad 100644 --- a/events/features/timing-framework/worker.js +++ b/events/features/timing-framework/worker.js @@ -1,19 +1,5 @@ import TestingManager from './testing.js'; -/** - * Gets the current tabId from sessionStorage - * This function is used by plugins that are not part of the worker context - * @returns {string} The current tabId - * @throws {Error} If tabId is not found in sessionStorage - */ -export function getCurrentTabId() { - const tabId = sessionStorage.getItem('chrono-box-tab-id'); - if (!tabId) { - throw new Error('tabId not found in sessionStorage. Ensure chrono-box is initialized first.'); - } - return tabId; -} - class TimingWorker { constructor() { this.tabId = null; @@ -86,6 +72,7 @@ class TimingWorker { */ static async getCurrentTimeFromAPI() { try { + // FIXME: get current time from Akamai API const response = await fetch('https://worldtimeapi.org/api/ip'); const data = await response.json(); return new Date(data.datetime).getTime(); diff --git a/events/scripts/utils.js b/events/scripts/utils.js index 7d6d36d5..47aeb118 100644 --- a/events/scripts/utils.js +++ b/events/scripts/utils.js @@ -287,3 +287,11 @@ export function parseMetadataPath(path, extraData = {}) { return currentValue || extraData[path] || ''; } + +export function getCurrentTabId() { + const tabId = sessionStorage.getItem('chrono-box-tab-id'); + if (!tabId) { + throw new Error('tabId not found in sessionStorage. Ensure chrono-box is initialized first.'); + } + return tabId; +} From ebfe7a328bc37817b01fd95d897b9d5a44bd364e Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Mon, 21 Jul 2025 22:46:58 +0530 Subject: [PATCH 56/93] key update --- events/blocks/chrono-box/chrono-box.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/events/blocks/chrono-box/chrono-box.js b/events/blocks/chrono-box/chrono-box.js index 2fd46324..47a3c913 100644 --- a/events/blocks/chrono-box/chrono-box.js +++ b/events/blocks/chrono-box/chrono-box.js @@ -158,6 +158,6 @@ export default async function init(el) { setTimeout(() => { console.log('setting video'); - metadataStore.set('video', 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'); + metadataStore.set('marketo-next', 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'); }, 10000); } From 00f102fcd84b19746fcce81e36fee7a5720936e2 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Wed, 23 Jul 2025 12:57:11 +0530 Subject: [PATCH 57/93] enhancements to mkto form --- rs/360-KCI-804/images/mktoTestFormConfig.js | 720 +++++++++++++++----- 1 file changed, 556 insertions(+), 164 deletions(-) diff --git a/rs/360-KCI-804/images/mktoTestFormConfig.js b/rs/360-KCI-804/images/mktoTestFormConfig.js index 1e994580..8f40f4fd 100644 --- a/rs/360-KCI-804/images/mktoTestFormConfig.js +++ b/rs/360-KCI-804/images/mktoTestFormConfig.js @@ -1,9 +1,12 @@ // ## -// ## Test Module - Just a rough test module to set the config of the form. +// ## Test Module - Just a rough test module to set the config of the form.11 // ## -if (typeof mkto_testing_loader != "function" && typeof mkto_testing_loader == "undefined") { - function getMktToken() { +if ( + typeof mczFrm_mkto_testing_loader != "function" && + typeof mczFrm_mkto_testing_loader == "undefined" +) { + async function getMktToken() { const storageKey = "mkt_tok"; let mktToken = ""; @@ -28,57 +31,55 @@ if (typeof mkto_testing_loader != "function" && typeof mkto_testing_loader == "u return mktToken; } - window.getMktToken = getMktToken(); + window.getMktToken = await getMktToken(); - let resourceLocation = ".adobe-connect"; - let resourceWatch = '.adobe-connect button[daa-ll*="Join"]'; - let mkto_testing_loader = () => { - //hide Join button + //hide Join button + var BASE_URL = "https://engage.marketo.com"; + var MUNCHKIN_ID = "360-KCI-804"; + var resourceLocation = ".adobe-connect"; + var resourceWatch = '.adobe-connect button[daa-ll*="Join"]'; + let mczFrm_mkto_testing_loader = () => { let cssFast = ` - button[daa-ll="Join the event-1--"] { - visibility: hidden !important; - opacity: 0 !important; - } - `; + button[daa-ll="Join the event-1--"] { + visibility: hidden !important; + opacity: 0 !important; + } + `; let cssLinkFast = document.createElement("style"); cssLinkFast.innerHTML = cssFast; document.head.appendChild(cssLinkFast); - const BASE_URL = "https://engage.marketo.com"; - const MUNCHKIN_ID = "360-KCI-804"; - let formID = 3131; - const urlParams = new URLSearchParams(window.location.search); - if (urlParams.has('formId')) { - formID = urlParams.get('formId'); - } - console.log('formID', formID); - let resourceFormHTML = ` -
-
- - - -
-
- `; +
+
+ + + +
+
+ `; const marketoCSSresource = "https://business.adobe.com/libs/blocks/marketo/marketo.css"; let marketoConfiguratorLink = "eyJmb3JtLnRlbXBsYXRlIjoicmVxdWVzdF9mb3JfaW5mb3JtYXRpb24iLCJmb3JtLnN1YnR5cGUiOiJyZXF1ZXN0X2Zvcl9pbmZvcm1hdGlvbiIsInByb2dyYW0uY2FtcGFpZ25pZHMuc2ZkYyI6IjcwMTE0MDAwMDAyWFl2SUFBVyIsInByb2dyYW0ucG9pIjoiTUFSS0VUT0VOR0FHRU1FTlRQTEFURk9STSIsImZvcm0uc3VjY2Vzcy5jb250ZW50IjoiaHR0cHM6Ly9idXNpbmVzcy5hZG9iZS5jb20vcmVzb3VyY2VzL2Vib29rcy9wcm92aW5nLXRoZS1pbXBhY3Qtb2YtbWFya2V0aW5nLW9uLXJldmVudWUvdGhhbmsteW91Lmh0bWwiLCJmb3JtLnN1Y2Nlc3MudHlwZSI6IiIsInByb2dyYW0uY29udGVudC50eXBlIjoiIiwicHJvZ3JhbS5jb250ZW50LmlkIjoiIiwiZmllbGRfdmlzaWJpbGl0eS5uYW1lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBob25lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnkiOiJyZXF1aXJlZCIsImZpZWxkX3Zpc2liaWxpdHkud2Vic2l0ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5mdW5jdGlvbmFsX2FyZWEiOiJGdW5jdGlvbmFsIEFyZWEtRFgiLCJmaWVsZF92aXNpYmlsaXR5LnN0YXRlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBvc3Rjb2RlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnlfc2l6ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5wcm9kdWN0cyI6ImhpZGRlbiIsImZpZWxkX2ZpbHRlcnMuaW5kdXN0cnkiOiJoaWRkZW4iLCJmaWVsZF9maWx0ZXJzLmpvYl9yb2xlIjoiYWxsIiwiZmllbGRfdmlzaWJpbGl0eS5jb21tZW50cyI6ImhpZGRlbiIsImZpZWxkX3Zpc2liaWxpdHkuZGVtbyI6ImhpZGRlbiIsInByb2dyYW0uY29wYXJ0bmVybmFtZXMiOiIiLCJwcm9ncmFtLmNhbXBhaWduaWRzLmV4dGVybmFsIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5yZXRvdWNoIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5vbnNpdGUiOiIiLCJwcm9ncmFtLmFkZGl0aW9uYWxfZm9ybV9pZCI6IiIsImZvcm0gaWQiOiIxNzIzIiwibWFya2V0byBtdW5ja2luIjoiMzYwLUtDSS04MDQiLCJtYXJrZXRvIGhvc3QiOiJlbmdhZ2UuYWRvYmUuY29tIiwiZm9ybSB0eXBlIjoibWFya2V0b19mb3JtIn0"; let marketoConfiguratorHTML = ` -
- -
-
Marketo Configurator
-
-
- `; +
+ +
+
Marketo Configurator
+
+
+ `; + + const cssLink = document.createElement("link"); + cssLink.rel = "stylesheet"; + cssLink.href = marketoCSSresource; + document.head.appendChild(cssLink); let marketoConfiguratorJSON = {}; try { @@ -89,43 +90,10 @@ if (typeof mkto_testing_loader != "function" && typeof mkto_testing_loader == "u console.error("Error parsing Marketo Configurator JSON", e); } - /* - Example of marktoConfiguratorJSON: - { - "form.template": "request_for_information", - "form.subtype": "request_for_information", - "program.campaignids.sfdc": "70114000002XYvIAAW", - "program.poi": "MARKETOENGAGEMENTPLATFORM", - "form.success.content": "https://business.adobe.com/resources/ebooks/proving-the-impact-of-marketing-on-revenue/thank-you.html", - "form.success.type": "", - "program.content.type": "", - "program.content.id": "", - "field_visibility.name": "required", - "field_visibility.phone": "required", - "field_visibility.company": "required", - "field_visibility.website": "required", - "field_filters.functional_area": "Functional Area-DX", - "field_visibility.state": "required", - "field_visibility.postcode": "required", - "field_visibility.company_size": "required", - "field_filters.products": "hidden", - "field_filters.industry": "hidden", - "field_filters.job_role": "all", - "field_visibility.comments": "hidden", - "field_visibility.demo": "hidden", - "program.copartnernames": "", - "program.campaignids.external": "", - "program.campaignids.retouch": "", - "program.campaignids.onsite": "", - "program.additional_form_id": "", - } - - - */ - let use_marketoConfiguratorLink = false; let mcz_marketoForm_pref_local = { + sync_profiles: {}, "marketo munckin": "360-KCI-804", "marketo host": "engage.adobe.com", "form id": "3131", @@ -159,7 +127,7 @@ if (typeof mkto_testing_loader != "function" && typeof mkto_testing_loader == "u event: { type: "adobe_connect", //connect_recording or video subtype: "flex_event", - id: "mczac114328", + id: "mcz114328", status: { viewport: { width: 1024, @@ -277,11 +245,6 @@ if (typeof mkto_testing_loader != "function" && typeof mkto_testing_loader == "u console.log("resourceLocation not found", resourceLocation); } - const cssLink = document.createElement("link"); - cssLink.rel = "stylesheet"; - cssLink.href = marketoCSSresource; - document.head.appendChild(cssLink); - loadScript(`${BASE_URL}/js/forms2/js/forms2.min.js`) .then(() => { const { MktoForms2 } = window; @@ -296,113 +259,542 @@ if (typeof mkto_testing_loader != "function" && typeof mkto_testing_loader == "u console.error("Error loading Marketo form"); }); - function sendRegSubmittedMessage() { - let iframe = document.getElementById("mcz-marketo-segment-iframe"); - if (iframe) { - iframe.contentWindow.postMessage({ type: "reg_submitted" }, "https://engage.adobe.com"); + window.addMunchkin = async function ( + munchkinId = "360-KCI-804", + pageFromEventId = "", + mktToken = "" + ) { + loadScript(`https://munchkin.marketo.net/munchkin.js`) + .then(() => { + Munchkin.init(munchkinId, { + customName: `Testing BACOM Connect UX ${pageFromEventId}`, + mkt_tok: mktToken, + }); + }) + .catch(() => { + console.error("Error loading Munchkin.js"); + }); + }; + + mczFrm_createProgramSyncIframe(); + }; + + window.mcz_marketoForm_adobe_connect_event = (event_url = "") => { + let final_url = ""; + if (event_url != "") { + final_url = event_url.trim(); + } + + if (document.querySelector(".marketo-form-wrapper")) { + document.querySelector(".marketo-form-wrapper").classList.add("hide"); + } + if (document.querySelector('.adobe-connect button[daa-ll*="Join"]')) { + document.querySelector('.adobe-connect button[daa-ll*="Join"]').click(); + } + console.log("adobe_connect_event", final_url); + mczFrm_sendMessage("reg_submitted", "root.program_profile"); + }; + + // + // + // + // + // + // + + function mczFrm_getTimeUntil(targetDate, nowDate) { + const timeUntil = targetDate - nowDate; + + if (timeUntil <= 0) { + return { days: 0, hours: 0, minutes: 0, seconds: 0, timeUntil }; + } + + const days = Math.floor(timeUntil / (1000 * 60 * 60 * 24)); + const hours = Math.floor((timeUntil % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); + const minutes = Math.floor((timeUntil % (1000 * 60 * 60)) / (1000 * 60)); + const seconds = Math.floor((timeUntil % (1000 * 60)) / 1000); + + return { days, hours, minutes, seconds, timeUntil }; + } + + function mczFrm_currentMarketoTime() { + let serverTimeOffset; + let serverTimeRaw = mcz_marketoForm_pref?.program?.marketo_asset?.time?.systemDateTime || null; + try { + if (serverTimeRaw) { + let serverTimeInitial = new Date(serverTimeRaw).getTime(); + if (!isNaN(serverTimeInitial)) { + let clientTimeInitial = new Date().getTime(); + serverTimeOffset = serverTimeInitial - clientTimeInitial; + } + } else { + serverTimeOffset = 0; + } + } catch (e) { + console.warn("Error getting server time offset", e); + serverTimeOffset = 0; + } + if (typeof serverTimeOffset === "undefined") { + return new Date(); + } + return new Date(new Date().getTime() + serverTimeOffset); + } + + var timeUntilInterval = null; + function mczFrm_updateTimeUntil() { + let base = window?.mcz_marketoForm_pref || {}; + let endDateTime = base?.program?.event?.dateTime?.pst?.dateTimeEnd || null; + let startDateTime = base?.program?.event?.dateTime?.pst?.dateTimeStart || null; + let nowDateTime = mczFrm_currentMarketoTime(); + let general_status = "pending"; + if (endDateTime == null || startDateTime == null || nowDateTime == null) { + console.warn("No end or now date time found for this event"); + return null; + } + + let adobe_connect_status = base?.program?.event?.adobe_connect?.status || null; + + if (adobe_connect_status == null) { + adobe_connect_status = {}; + } + + let endDate = new Date(endDateTime); + let startDate = new Date(startDateTime); + let nowDate = new Date(nowDateTime); + let timeUntilEnds = mczFrm_getTimeUntil(endDate, nowDate); + let timeUntilStart = mczFrm_getTimeUntil(startDate, nowDate); + + let stillReview = true; + + // Reset status flags + adobe_connect_status.is_starting_soon = false; + adobe_connect_status.is_starting_in_5_minutes = false; + adobe_connect_status.is_starting_in_1_minute = false; + adobe_connect_status.is_halfway_through = false; + adobe_connect_status.about_to_end = false; + adobe_connect_status.has_ended = false; + adobe_connect_status.has_finished = false; + adobe_connect_status.can_enter = false; + adobe_connect_status.can_attend = false; + adobe_connect_status.can_register = false; + adobe_connect_status.has_started = false; + adobe_connect_status.is_reg_open = false; + adobe_connect_status.is_reg_closed = false; + general_status = "register"; + + if (timeUntilInterval) { + clearInterval(timeUntilInterval); + } + + // Set timing status flags based on time until start + if (timeUntilStart.timeUntil > 0 && stillReview) { + if (timeUntilStart.minutes <= 10) { + adobe_connect_status.is_starting_soon = true; + } + if (timeUntilStart.minutes <= 5) { + adobe_connect_status.is_starting_in_5_minutes = true; + } + if (timeUntilStart.minutes <= 1) { + adobe_connect_status.is_starting_in_1_minute = true; } } - window.mcz_marketoForm_adobe_connect_event = (event_url = "") => { - let final_url = ""; - if (event_url != "") { - final_url = event_url.trim(); + let duration = mczFrm_getTimeUntil(endDate, startDate); + base.program.event.dateTime.duration = duration; + + let remaining = mczFrm_getTimeUntil(endDate, nowDate); + base.program.event.dateTime.remaining = remaining; + + // Calculate halfway point using total milliseconds for accuracy + if (duration?.timeUntil > 0 && stillReview) { + let half_duration_ms = duration.timeUntil / 2; + if (remaining?.timeUntil <= half_duration_ms && remaining?.timeUntil > 0) { + adobe_connect_status.is_halfway_through = true; } + } + + // Check if event is about to end + if (remaining?.timeUntil > 0 && remaining.minutes <= 10 && stillReview) { + adobe_connect_status.about_to_end = true; + } - if (document.querySelector(".marketo-form-wrapper")) { - document.querySelector(".marketo-form-wrapper").classList.add("hide"); + //check if finished + if ( + adobe_connect_status.has_started && + remaining?.timeUntil > 0 && + remaining.minutes <= 2 && + stillReview + ) { + adobe_connect_status.has_ended = true; + adobe_connect_status.has_finished = true; + adobe_connect_status.is_reg_open = false; + adobe_connect_status.is_reg_closed = true; + adobe_connect_status.can_enter = false; + adobe_connect_status.can_attend = false; + adobe_connect_status.can_register = false; + adobe_connect_status.has_started = true; + general_status = "finished"; + stillReview = false; + } + + //open_minutes and close_minutes + let open_minutes = base?.program?.event?.dateTime?.pst?.open_minutes || 10; //you can join 10 minutes before the event starts + let close_minutes = base?.program?.event?.dateTime?.pst?.close_minutes || 999; //you can join 999 minutes after the event starts + + //workout if the event is open or closed + let doorsOpen = false; + if (timeUntilStart?.minutes > 0 && stillReview) { + if (timeUntilStart?.minutes <= open_minutes) { + doorsOpen = true; + adobe_connect_status.can_enter = true; + adobe_connect_status.can_attend = true; + adobe_connect_status.can_register = true; + adobe_connect_status.has_started = true; + adobe_connect_status.has_ended = false; + adobe_connect_status.is_reg_open = true; + adobe_connect_status.is_reg_closed = false; + general_status = "live"; + stillReview = false; } - if (document.querySelector('.adobe-connect button[daa-ll*="Join"]')) { - document.querySelector('.adobe-connect button[daa-ll*="Join"]').click(); + } + if (doorsOpen) { + if (duration?.minutes >= close_minutes && stillReview) { + doorsOpen = false; + adobe_connect_status.can_enter = false; + adobe_connect_status.can_attend = false; + adobe_connect_status.can_register = false; + adobe_connect_status.has_started = true; + adobe_connect_status.is_reg_open = false; + adobe_connect_status.is_reg_closed = true; + general_status = "live"; + stillReview = false; } - console.log("adobe_connect_event", final_url); - sendRegSubmittedMessage(); + } + + base.program.event.dateTime.timeUntil = { + starts: timeUntilStart, + ends: timeUntilEnds, }; + adobe_connect_status.overall = general_status; + base.program.event.status = general_status; + base.program.event.id = window?.programId || null; - function createProfileSyncIframe() { - let mktToken = getMktToken(); - let pageFromEventId = mcz_marketoForm_pref.program.event.id || ""; - if (pageFromEventId == "") { - console.log("No event id found, skipping profile sync iframe."); - return; + console.log("timeUntilStart", timeUntilStart); + + if (timeUntilStart.minutes <= 30) { + if (!timeUntilInterval) { + timeUntilInterval = setInterval(mczFrm_updateTimeUntil, 1000); } - let baseURL = `https://engage.adobe.com/${pageFromEventId}.html`; - - if (mktToken) { - const iframe = document.createElement("iframe"); - let finalURL = `${baseURL}?mkt_tok=${mktToken}`; - - iframe.sandbox = "allow-scripts allow-same-origin"; - iframe.src = finalURL; - iframe.style.display = "none"; - iframe.id = "mcz-marketo-segment-iframe"; - document.body.appendChild(iframe); - console.log("Profile sync iframe added with URL:", iframe.src); - } else { - console.log(`No ${storageKey} found, skipping profile sync iframe.`); + } else { + if (timeUntilInterval) { + clearInterval(timeUntilInterval); + timeUntilInterval = null; } } + } - window.addEventListener("message", (event) => { - let config = { - allowedOrigins: ["https://engage.adobe.com", "https://business.adobe.com"], - }; + function mczFrm_ACE_confirmURL(url_name = "", url = "") { + try { + let confirmLocation = + window.mcz_marketoForm_pref?.program?.event?.adobe_connect?.urls?.[url_name] || null; + if (confirmLocation == null) { + return false; + } + + let current_status = confirmLocation?.valid_url || false; + if (current_status) { + return true; + } - let eventOrigin = new URL(event.origin); - let allowedToPass = false; - for (let i = 0; i < config.allowedOrigins.length; i++) { - let allowedOriginURL = new URL(config.allowedOrigins[i]); - if ( - eventOrigin.host === allowedOriginURL.host && - eventOrigin.protocol === allowedOriginURL.protocol && - eventOrigin.port === allowedOriginURL.port - ) { - allowedToPass = true; - break; + if (url.trim() == "") { + //get the url from the config and we will validate it. + url = confirmLocation.url || ""; + if (url.trim() == "") { + return false; } } - if (!allowedToPass) { - return; + + confirmLocation.url = url; + + try { + confirmLocation.url_obj = new URL(url); + confirmLocation.valid_url = true; + } catch (e) { + confirmLocation.valid_url = false; + confirmLocation.url_obj = {}; + confirmLocation.url = ""; + return false; } - //segment update - if (event.data && event.data.type === "profile_acc") { - console.log("Received profile data from iframe:", event.data); - if (event.data.mcz_marketoForm_pref) { - window.mcz_marketoForm_pref = window.mcz_marketoForm_pref || {}; - window.mcz_marketoForm_pref.profile = window.mcz_marketoForm_pref.profile || {}; - window.mcz_marketoForm_pref.profile.acc = event.data.mcz_marketoForm_pref; - } + return true; + } catch (e) { + return false; + } + } + //* + //* + //* + //* Communication frunctions + //* + async function mczFrm_createProgramSyncIframe() { + let mktToken = window.getMktToken; + let pageFromEventId = mcz_marketoForm_pref.program.event.id || ""; + if (pageFromEventId == "") { + console.log("No event id found, skipping profile sync iframe."); + return; + } + + let munchkinId = MUNCHKIN_ID || "360-KCI-804"; + addMunchkin(munchkinId, pageFromEventId, mktToken); + let programIDOnly = pageFromEventId.replace(/[^0-9]/g, ""); + let programfromStorage = await mczFrm_aquireFromStorage(`ev__${programIDOnly}`); + if (programfromStorage) { + console.log("MCZ Form, Updating DL from storage:", programfromStorage); + mczFrm_updateDL(programfromStorage); + } + + let baseURL = `https://engage.adobe.com/${pageFromEventId}.html`; + if (mktToken) { + baseURL = `${baseURL}?mkt_tok=${mktToken}`; + } + + const iframe = document.createElement("iframe"); + iframe.sandbox = "allow-scripts allow-same-origin"; + iframe.src = baseURL; + iframe.style.display = "none"; + iframe.id = "mcz-marketo-program-iframe"; + document.body.appendChild(iframe); + console.log("Profile sync iframe added with URL:", iframe.src); + } + + function mczFrm_aquireFromStorage(lookupKey = null) { + const now = new Date().getTime(); + + let itemStr = null; + itemStr = sessionStorage.getItem(lookupKey); + if (!itemStr) { + itemStr = localStorage.getItem(lookupKey); + } + if (!itemStr) { + return null; + } + + try { + const item = JSON.parse(itemStr); + const shelfLife = item?.shelf_life || 0; + const timestamp = item?.timestamp || 0; + const expires = item?.expires || 0; + + if (now - timestamp > shelfLife || now > expires) { + sessionStorage.removeItem(lookupKey); + localStorage.removeItem(lookupKey); + console.log(`MCZ RefData: Expired program removed from ${lookupKey}`); + return null; } - //membership update - if (event.data && event.data.type === "program_profile") { - console.log("Received membership data from iframe:", event.data); + return item; + } catch (e) { + return null; + } + } - let description = event.data.description || ""; - if (description == "") { - description = "program_profile"; - } + async function mczFrm_saveRefs(baseAlias = null, refStorageKey = null) { + if (!refStorageKey) { + console.warn("No reference storage key found"); + return; + } - if (event.data.mcz_marketoForm_pref) { - window.mcz_marketoForm_pref = window.mcz_marketoForm_pref || {}; - window.mcz_marketoForm_pref.program_profile = - window.mcz_marketoForm_pref.program_profile || {}; - - let dataLabel = "data-mcz-dl-status"; - let elements = document.querySelectorAll(`[${dataLabel}]`); - let timeNow = new Date().getTime(); - for (let i = 0; i < elements.length; i++) { - let element = elements[i]; - element.setAttribute(dataLabel, event.data.mcz_marketoForm_pref.program_profile.status); - element.setAttribute(`${dataLabel}-dt`, timeNow); - } + let existingRefs = []; + let newRefs = []; + try { + existingRefs = JSON.parse(localStorage.getItem(refStorageKey) || "[]"); + } catch (e) { + console.warn("Error parsing refStorage", e); + existingRefs = []; + } + + const dataProfileKeys = existingRefs || []; + const now = new Date().getTime(); + + for (let key of dataProfileKeys) { + const lookupKey = key; + let itemStr = null; + itemStr = sessionStorage.getItem(lookupKey); + if (!itemStr) { + itemStr = localStorage.getItem(lookupKey); + } + if (!itemStr) { + continue; + } + + try { + const item = JSON.parse(itemStr); + const shelfLife = item?.shelf_life || 0; + const timestamp = item?.timestamp || 0; + const expires = item?.expires || 0; + + if (now - timestamp > shelfLife || now > expires) { + sessionStorage.removeItem(lookupKey); + localStorage.removeItem(lookupKey); + console.log(`MCZ RefData: Expired ref removed from ${lookupKey}`); + } else { + newRefs.push(lookupKey); } + } catch (e) { + console.warn(`Error parsing dataProfile for key: ${lookupKey}`, e); + sessionStorage.removeItem(lookupKey); + localStorage.removeItem(lookupKey); } - }); + } - createProfileSyncIframe(); - }; + if ( + baseAlias != null && + newRefs.indexOf(baseAlias) == -1 && + existingRefs.indexOf(baseAlias) == -1 + ) { + newRefs.push(baseAlias); + } + + localStorage.setItem(refStorageKey, JSON.stringify(newRefs)); + console.log("MCZ RefData: Updated refs in refStorage", newRefs); + } + + async function mczFrm_saveMsg(message) { + try { + const saveAlias = message?.alias || null; + const refStorageKey = message?.refStorage || null; + const location = message?.location || "local"; + const dataStr = JSON.stringify(message); + const sizeInBytes = new Blob([dataStr]).size; + const sizeInMB = sizeInBytes / (1024 * 1024); + + if (sizeInMB > 2) { + console.warn(`MCZ RefData: Large data size (${sizeInMB.toFixed(2)}MB)`); + } + if (!saveAlias) { + console.warn("No save alias found"); + return; + } + + if (location == "session") { + sessionStorage.setItem(saveAlias, dataStr); + } else { + localStorage.setItem(saveAlias, dataStr); + } + + mczFrm_saveRefs(saveAlias, refStorageKey); + } catch (storageError) { + console.warn("Storage error:", storageError); + } + } + + window.addEventListener("message", (event) => { + let config = { + allowedOrigins: ["https://engage.adobe.com", "https://business.adobe.com"], + }; + let eventOrigin = new URL(event.origin); + let allowedToPass = false; + for (let i = 0; i < config.allowedOrigins.length; i++) { + let allowedOriginURL = new URL(config.allowedOrigins[i]); + if ( + eventOrigin.host === allowedOriginURL.host && + eventOrigin.protocol === allowedOriginURL.protocol && + eventOrigin.port === allowedOriginURL.port + ) { + allowedToPass = true; + break; + } + } + if (event.data && event?.data?.type !== "mcz_marketoForm_pref_sync") { + allowedToPass = false; + } + if (!allowedToPass) { + return; + } + console.log("MCZ RefData Received:", event.data); + if (event.data && event?.data?.target_path !== null && event?.data?.target_attribute !== null) { + let save = event?.data?.save || false; + mczFrm_updateDL(event?.data); + if (save) { + mczFrm_saveMsg(event?.data); + } + } + }); + + function mczFrm_updateDL(data = null) { + if (data == null) { + return; + } + let targetPath = data?.target_path || null; + if (targetPath == null) { + return; + } + let program_type = data?.data?.program?.type || "default"; + let program_status = "default"; + + let this_data = JSON.parse(JSON.stringify(data?.data)); + if (targetPath == "root.program_profile") { + window.mcz_marketoForm_pref.program_profile = this_data; + } else if (targetPath == "root.profile") { + window.mcz_marketoForm_pref.profile = this_data; + } else if (targetPath == "root.form") { + window.mcz_marketoForm_pref.form = this_data; + } else if (targetPath == "root.profile.acc") { + window.mcz_marketoForm_pref.profile.acc = this_data; + } else if (targetPath == "root.program") { + window.mcz_marketoForm_pref.program = this_data; + program_type = this_data?.type || "default"; + } else if (targetPath == "root.program.event") { + window.mcz_marketoForm_pref.program.event = this_data; + program_type = this_data?.type || "default"; + } + + if (window.mcz_marketoForm_pref?.program?.type == "event") { + mczFrm_updateTimeUntil(); + if (window.mcz_marketoForm_pref?.program?.event?.type == "adobe_connect") { + program_type = "adobe_connect"; + program_status = + window.mcz_marketoForm_pref?.program?.event?.adobe_connect?.status?.overall || "default"; + } + } + + function mczFrm_statusLbls(program_type = "", program_status = "") { + if (program_type == "" || program_status == "") { + console.log("No program type or status found"); + return; + } + + let dataLabel = "data-mcz-dl-status"; + let elements = document.querySelectorAll(`[${dataLabel}]`); + let timeNow = new Date().getTime(); + for (let i = 0; i < elements.length; i++) { + let element = elements[i]; + element.setAttribute(`${dataLabel}-dt`, timeNow); + element.setAttribute(`${dataLabel}-type`, program_type); + element.setAttribute(`${dataLabel}`, program_status); + } + } + + console.log("Status Labels:", program_type, program_status); + + mczFrm_statusLbls(program_type, program_status); + } + + function mczFrm_sendMessage(msgName = null, targetPath = "root.program", data = {}) { + let iframe = document.getElementById("mcz-marketo-program-iframe"); + if (iframe) { + let message = { + type: "mcz_marketoForm_pref_sync", + data: { + target_path: targetPath, + data: data, + }, + }; + + iframe.contentWindow.postMessage(message, "https://engage.adobe.com"); + } else { + console.warn("No iframe found"); + } + } - window.mkto_testing_loader = mkto_testing_loader; let maxTries = 1000; let checkResourceLocation = async () => { if (maxTries <= 0) { @@ -411,7 +803,7 @@ if (typeof mkto_testing_loader != "function" && typeof mkto_testing_loader == "u } maxTries--; if (document.querySelector(resourceWatch)) { - window.mkto_testing_loader(); + mczFrm_mkto_testing_loader(); } else { await new Promise((resolve) => setTimeout(resolve, 25)); checkResourceLocation(); @@ -421,4 +813,4 @@ if (typeof mkto_testing_loader != "function" && typeof mkto_testing_loader == "u } // ## -// ## +// ## \ No newline at end of file From da653f21bd2a5ac706aee553338ce429d5977b43 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Wed, 23 Jul 2025 14:09:20 +0530 Subject: [PATCH 58/93] enhancing adobeconnect --- events/blocks/adobe-connect/adobe-connect.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/events/blocks/adobe-connect/adobe-connect.js b/events/blocks/adobe-connect/adobe-connect.js index 5a733ab2..cd7f7b82 100644 --- a/events/blocks/adobe-connect/adobe-connect.js +++ b/events/blocks/adobe-connect/adobe-connect.js @@ -43,9 +43,9 @@ export default async function init(el) { el.setAttribute('data-mcz-dl-status', 'loading'); h2.remove(); - const button = createTag('button', { class: 'hidden' }, 'Join the event', { parent: el }); + // const button = createTag('button', { class: 'hidden' }, 'Join the event', { parent: el }); - button.addEventListener('click', () => { + // button.addEventListener('click', () => { const searchParams = getSearchParamsFromCurrentUrl(); if (validateUrl(window.join_url)) { @@ -79,9 +79,9 @@ export default async function init(el) { overlay.remove(); }, 7000); - button.remove(); - document.body.querySelector('#webinar-marketo-form')?.remove(); - }); + // button.remove(); + // document.body.querySelector('#webinar-marketo-form')?.remove(); + // }); function mcz_marketoForm_adobe_connect_event() { From 4f9d066c7d4bf6e54b318f8c47af9805df5d7d95 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Wed, 23 Jul 2025 15:40:32 +0530 Subject: [PATCH 59/93] code changes --- events/blocks/adobe-connect/adobe-connect.css | 30 +- events/blocks/adobe-connect/adobe-connect.js | 127 ++--- events/blocks/chrono-box/chrono-box.js | 68 ++- rs/360-KCI-804/images/mktoTestFormConfig.js | 472 +++++++++--------- 4 files changed, 335 insertions(+), 362 deletions(-) diff --git a/events/blocks/adobe-connect/adobe-connect.css b/events/blocks/adobe-connect/adobe-connect.css index 33ed58ac..0bec9152 100644 --- a/events/blocks/adobe-connect/adobe-connect.css +++ b/events/blocks/adobe-connect/adobe-connect.css @@ -1,34 +1,10 @@ .adobe-connect { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; width: 100%; - padding: 0 16px; + padding: 0; + margin: 0; } + .adobe-connect .fullwidth { width: 100%; height: 900px; - } - -.adobe-connect button { - font-size: var(--type-body-s-size); - background-color: var(--link-color); - min-width: 114px; - height: 40px; - line-height: 20px; - padding: 9px 16px; - border: 0; - border-radius: 24px; - color: #fff; - font-weight: 700; - box-shadow: none; - margin: 0 auto; - cursor: pointer; - transition: background-color 0.13s, color 0.13s; -} - -.adobe-connect .hidden { - visibility: hidden !important; - opacity: 0 !important; } \ No newline at end of file diff --git a/events/blocks/adobe-connect/adobe-connect.js b/events/blocks/adobe-connect/adobe-connect.js index cd7f7b82..a3225d06 100644 --- a/events/blocks/adobe-connect/adobe-connect.js +++ b/events/blocks/adobe-connect/adobe-connect.js @@ -1,4 +1,4 @@ -import { LIBS } from '../../scripts/utils.js'; +import { LIBS, getMetadata } from '../../scripts/utils.js'; const { createTag } = await import(`${LIBS}/utils/utils.js`); @@ -43,97 +43,44 @@ export default async function init(el) { el.setAttribute('data-mcz-dl-status', 'loading'); h2.remove(); - // const button = createTag('button', { class: 'hidden' }, 'Join the event', { parent: el }); - // button.addEventListener('click', () => { - const searchParams = getSearchParamsFromCurrentUrl(); + const searchParams = getSearchParamsFromCurrentUrl(); - if (validateUrl(window.join_url)) { - url = window.join_url; - console.log("join_url in Window", window.join_url); - } - url = addSearchParams(url, searchParams); - - // Create overlay - const overlay = createTag('div', { - class: 'iframe-overlay', - style: 'position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.9); display: flex; align-items: center; justify-content: center; z-index: 1000;', - }, '', { parent: el }); - - // Create loading text - createTag('div', { - style: 'font-size: 1.2em; color: #333;', - }, 'Loading event...', { parent: overlay }); - - // Create iframe - createTag('iframe', { - src: url, - frameborder: '0', - allowfullscreen: 'true', - class: 'fullwidth', - style: 'position: relative; z-index: 1;', - }, '', { parent: el }); - - // Remove overlay after 7 seconds - setTimeout(() => { - overlay.remove(); - }, 7000); - - // button.remove(); - // document.body.querySelector('#webinar-marketo-form')?.remove(); - // }); - - function mcz_marketoForm_adobe_connect_event() { - - if (window.mcz_marketoForm_pref?.form?.success?.type === "adobe_connect") { - const eventUrl = window.mcz_marketoForm_pref?.form?.success?.content; - window.join_url = eventUrl; - } - - if (document.querySelector(".marketo-form-wrapper")) { - document.querySelector(".marketo-form-wrapper").classList.add("hide"); - } - // console.log("adobe_connect_event in Events", eventUrl); - - const joinButton = document.querySelector('.adobe-connect button[daa-ll*="Join"]'); - if (joinButton) { - document.querySelector('.adobe-connect button[daa-ll*="Join"]').click(); - } - }; - - // Debounce function to limit rapid calls - function debounce(func, wait) { - let timeout; - return function executedFunction(...args) { - const later = () => { - clearTimeout(timeout); - func(...args); - }; - clearTimeout(timeout); - timeout = setTimeout(later, wait); - }; + if(getMetadata('adobe-connect-url')) { + url = getMetadata('adobe-connect-url'); + } else { + console.log('No adobe-connect-url found'); + return; } - // Debounced callback for observer - const debouncedCallback = debounce(() => { - const status = el.getAttribute('data-mcz-dl-status') - console.log('Attribute "data-mcz-dl-status" changed to', - el.getAttribute('data-mcz-dl-status')); - if (status === 'active') { - window.mcz_marketoForm_adobe_connect_event(); - } - }, 300); // 300ms debounce delay - - const observer = new MutationObserver((mutationsList) => { - mutationsList.forEach((mutation) => { - if (mutation.type === 'attributes') { - debouncedCallback(); - } - }); - }); - - observer.observe(el, { - attributes: true, // Observe attribute changes - attributeFilter: ['data-mcz-dl-status'], // Optional: filter specific attributes - }); + // if (validateUrl(window.join_url)) { + // url = window.join_url; + // console.log("join_url in Window", window.join_url); + // } + url = addSearchParams(url, searchParams); + + // Create overlay + const overlay = createTag('div', { + class: 'iframe-overlay', + style: 'position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.9); display: flex; align-items: center; justify-content: center; z-index: 1000;', + }, '', { parent: el }); + + // Create loading text + createTag('div', { + style: 'font-size: 1.2em; color: #333;', + }, 'Loading event...', { parent: overlay }); + + // Create iframe + createTag('iframe', { + src: url, + frameborder: '0', + allowfullscreen: 'true', + class: 'fullwidth', + style: 'position: relative; z-index: 1;', + }, '', { parent: el }); + + // Remove overlay after 7 seconds + setTimeout(() => { + overlay.remove(); + }, 7000); } diff --git a/events/blocks/chrono-box/chrono-box.js b/events/blocks/chrono-box/chrono-box.js index cbb833c1..b4c88298 100644 --- a/events/blocks/chrono-box/chrono-box.js +++ b/events/blocks/chrono-box/chrono-box.js @@ -1,4 +1,4 @@ -import { metadataStore } from '../../features/timing-framework/plugins/metadata/plugin.js'; +// import { metadataStore } from '../../features/timing-framework/plugins/metadata/plugin.js'; import { readBlockConfig, LIBS, getMetadata } from '../../scripts/utils.js'; function buildScheduleDoubleLinkedList(entries) { @@ -171,8 +171,66 @@ export default async function init(el) { }); }; - setTimeout(() => { - console.log('setting video'); - metadataStore.set('marketo-next', 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'); - }, 10000); + setMetadata('adobe-connect-url', 'https://newadmin.dev.adobeconnect.com/gbajaj?guestname=Participant&proto=true'); + + // setTimeout(() => { + // console.log('setting video'); + // metadataStore.set('marketo-next', 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'); + // }, 10000); + + function mczMarketoFormAdobeConnectEvent() { + if (window.mcz_marketoForm_pref?.form?.success?.type === 'adobe_connect') { + const eventUrl = window.mcz_marketoForm_pref?.form?.success?.content; + setMetadata('adobe-connect-url', eventUrl); + // window.join_url = eventUrl; + } + + // if (document.querySelector(".marketo-form-wrapper")) { + // document.querySelector(".marketo-form-wrapper").classList.add("hide"); + // } + // // console.log("adobe_connect_event in Events", eventUrl); + + // const joinButton = document.querySelector('.adobe-connect button[daa-ll*="Join"]'); + // if (joinButton) { + // document.querySelector('.adobe-connect button[daa-ll*="Join"]').click(); + // } + } + + // Debounce function to limit rapid calls + function debounce(func, wait) { + let timeout; + return function executedFunction(...args) { + const later = () => { + clearTimeout(timeout); + func(...args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; + } + + // Debounced callback for observer + const debouncedCallback = debounce(() => { + const status = el.getAttribute('data-mcz-dl-status'); + console.log( + 'Attribute "data-mcz-dl-status" changed to', + el.getAttribute('data-mcz-dl-status'), + ); + if (status === 'active') { + mczMarketoFormAdobeConnectEvent(); + } + }, 300); // 300ms debounce delay + + const observer = new MutationObserver((mutationsList) => { + mutationsList.forEach((mutation) => { + if (mutation.type === 'attributes') { + debouncedCallback(); + } + }); + }); + + observer.observe(el, { + attributes: true, // Observe attribute changes + attributeFilter: ['data-mcz-dl-status'], // Optional: filter specific attributes + }); } diff --git a/rs/360-KCI-804/images/mktoTestFormConfig.js b/rs/360-KCI-804/images/mktoTestFormConfig.js index 8f40f4fd..724e60ce 100644 --- a/rs/360-KCI-804/images/mktoTestFormConfig.js +++ b/rs/360-KCI-804/images/mktoTestFormConfig.js @@ -3,12 +3,12 @@ // ## if ( - typeof mczFrm_mkto_testing_loader != "function" && - typeof mczFrm_mkto_testing_loader == "undefined" + typeof mczFrm_mkto_testing_loader !== 'function' + && typeof mczFrm_mkto_testing_loader === 'undefined' ) { async function getMktToken() { - const storageKey = "mkt_tok"; - let mktToken = ""; + const storageKey = 'mkt_tok'; + let mktToken = ''; if (window.__mktTokVal && window.__mktTokVal?.trim()?.length > 0) { return window.__mktTokVal; @@ -24,7 +24,7 @@ if ( console.warn(`Could not save ${storageKey} to storage`, e); } } else { - mktToken = sessionStorage.getItem(storageKey) || localStorage.getItem(storageKey) || ""; + mktToken = sessionStorage.getItem(storageKey) || localStorage.getItem(storageKey) || ''; } window.__mktTokVal = mktToken; @@ -33,25 +33,25 @@ if ( window.getMktToken = await getMktToken(); - //hide Join button + // hide Join button - var BASE_URL = "https://engage.marketo.com"; - var MUNCHKIN_ID = "360-KCI-804"; - var resourceLocation = ".adobe-connect"; - var resourceWatch = '.adobe-connect button[daa-ll*="Join"]'; - let mczFrm_mkto_testing_loader = () => { - let cssFast = ` + const BASE_URL = 'https://engage.marketo.com'; + const MUNCHKIN_ID = '360-KCI-804'; + const resourceLocation = '.chrono-box'; + const resourceWatch = '.chrono-box'; + const mczFrm_mkto_testing_loader = () => { + const cssFast = ` button[daa-ll="Join the event-1--"] { visibility: hidden !important; opacity: 0 !important; } `; - let cssLinkFast = document.createElement("style"); + const cssLinkFast = document.createElement('style'); cssLinkFast.innerHTML = cssFast; document.head.appendChild(cssLinkFast); - let formID = 3131; - let resourceFormHTML = ` + const formID = 3131; + const resourceFormHTML = `
@@ -61,11 +61,10 @@ if (
`; - const marketoCSSresource = "https://business.adobe.com/libs/blocks/marketo/marketo.css"; + const marketoCSSresource = 'https://business.adobe.com/libs/blocks/marketo/marketo.css'; - let marketoConfiguratorLink = - "eyJmb3JtLnRlbXBsYXRlIjoicmVxdWVzdF9mb3JfaW5mb3JtYXRpb24iLCJmb3JtLnN1YnR5cGUiOiJyZXF1ZXN0X2Zvcl9pbmZvcm1hdGlvbiIsInByb2dyYW0uY2FtcGFpZ25pZHMuc2ZkYyI6IjcwMTE0MDAwMDAyWFl2SUFBVyIsInByb2dyYW0ucG9pIjoiTUFSS0VUT0VOR0FHRU1FTlRQTEFURk9STSIsImZvcm0uc3VjY2Vzcy5jb250ZW50IjoiaHR0cHM6Ly9idXNpbmVzcy5hZG9iZS5jb20vcmVzb3VyY2VzL2Vib29rcy9wcm92aW5nLXRoZS1pbXBhY3Qtb2YtbWFya2V0aW5nLW9uLXJldmVudWUvdGhhbmsteW91Lmh0bWwiLCJmb3JtLnN1Y2Nlc3MudHlwZSI6IiIsInByb2dyYW0uY29udGVudC50eXBlIjoiIiwicHJvZ3JhbS5jb250ZW50LmlkIjoiIiwiZmllbGRfdmlzaWJpbGl0eS5uYW1lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBob25lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnkiOiJyZXF1aXJlZCIsImZpZWxkX3Zpc2liaWxpdHkud2Vic2l0ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5mdW5jdGlvbmFsX2FyZWEiOiJGdW5jdGlvbmFsIEFyZWEtRFgiLCJmaWVsZF92aXNpYmlsaXR5LnN0YXRlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBvc3Rjb2RlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnlfc2l6ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5wcm9kdWN0cyI6ImhpZGRlbiIsImZpZWxkX2ZpbHRlcnMuaW5kdXN0cnkiOiJoaWRkZW4iLCJmaWVsZF9maWx0ZXJzLmpvYl9yb2xlIjoiYWxsIiwiZmllbGRfdmlzaWJpbGl0eS5jb21tZW50cyI6ImhpZGRlbiIsImZpZWxkX3Zpc2liaWxpdHkuZGVtbyI6ImhpZGRlbiIsInByb2dyYW0uY29wYXJ0bmVybmFtZXMiOiIiLCJwcm9ncmFtLmNhbXBhaWduaWRzLmV4dGVybmFsIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5yZXRvdWNoIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5vbnNpdGUiOiIiLCJwcm9ncmFtLmFkZGl0aW9uYWxfZm9ybV9pZCI6IiIsImZvcm0gaWQiOiIxNzIzIiwibWFya2V0byBtdW5ja2luIjoiMzYwLUtDSS04MDQiLCJtYXJrZXRvIGhvc3QiOiJlbmdhZ2UuYWRvYmUuY29tIiwiZm9ybSB0eXBlIjoibWFya2V0b19mb3JtIn0"; - let marketoConfiguratorHTML = ` + const marketoConfiguratorLink = 'eyJmb3JtLnRlbXBsYXRlIjoicmVxdWVzdF9mb3JfaW5mb3JtYXRpb24iLCJmb3JtLnN1YnR5cGUiOiJyZXF1ZXN0X2Zvcl9pbmZvcm1hdGlvbiIsInByb2dyYW0uY2FtcGFpZ25pZHMuc2ZkYyI6IjcwMTE0MDAwMDAyWFl2SUFBVyIsInByb2dyYW0ucG9pIjoiTUFSS0VUT0VOR0FHRU1FTlRQTEFURk9STSIsImZvcm0uc3VjY2Vzcy5jb250ZW50IjoiaHR0cHM6Ly9idXNpbmVzcy5hZG9iZS5jb20vcmVzb3VyY2VzL2Vib29rcy9wcm92aW5nLXRoZS1pbXBhY3Qtb2YtbWFya2V0aW5nLW9uLXJldmVudWUvdGhhbmsteW91Lmh0bWwiLCJmb3JtLnN1Y2Nlc3MudHlwZSI6IiIsInByb2dyYW0uY29udGVudC50eXBlIjoiIiwicHJvZ3JhbS5jb250ZW50LmlkIjoiIiwiZmllbGRfdmlzaWJpbGl0eS5uYW1lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBob25lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnkiOiJyZXF1aXJlZCIsImZpZWxkX3Zpc2liaWxpdHkud2Vic2l0ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5mdW5jdGlvbmFsX2FyZWEiOiJGdW5jdGlvbmFsIEFyZWEtRFgiLCJmaWVsZF92aXNpYmlsaXR5LnN0YXRlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBvc3Rjb2RlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnlfc2l6ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5wcm9kdWN0cyI6ImhpZGRlbiIsImZpZWxkX2ZpbHRlcnMuaW5kdXN0cnkiOiJoaWRkZW4iLCJmaWVsZF9maWx0ZXJzLmpvYl9yb2xlIjoiYWxsIiwiZmllbGRfdmlzaWJpbGl0eS5jb21tZW50cyI6ImhpZGRlbiIsImZpZWxkX3Zpc2liaWxpdHkuZGVtbyI6ImhpZGRlbiIsInByb2dyYW0uY29wYXJ0bmVybmFtZXMiOiIiLCJwcm9ncmFtLmNhbXBhaWduaWRzLmV4dGVybmFsIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5yZXRvdWNoIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5vbnNpdGUiOiIiLCJwcm9ncmFtLmFkZGl0aW9uYWxfZm9ybV9pZCI6IiIsImZvcm0gaWQiOiIxNzIzIiwibWFya2V0byBtdW5ja2luIjoiMzYwLUtDSS04MDQiLCJtYXJrZXRvIGhvc3QiOiJlbmdhZ2UuYWRvYmUuY29tIiwiZm9ybSB0eXBlIjoibWFya2V0b19mb3JtIn0'; + const marketoConfiguratorHTML = `
@@ -76,58 +75,58 @@ if (
`; - const cssLink = document.createElement("link"); - cssLink.rel = "stylesheet"; + const cssLink = document.createElement('link'); + cssLink.rel = 'stylesheet'; cssLink.href = marketoCSSresource; document.head.appendChild(cssLink); let marketoConfiguratorJSON = {}; try { marketoConfiguratorJSON = JSON.parse( - decodeURIComponent(escape(window.atob(marketoConfiguratorLink))) + decodeURIComponent(escape(window.atob(marketoConfiguratorLink))), ); } catch (e) { - console.error("Error parsing Marketo Configurator JSON", e); + console.error('Error parsing Marketo Configurator JSON', e); } - let use_marketoConfiguratorLink = false; + const use_marketoConfiguratorLink = false; - let mcz_marketoForm_pref_local = { + const mcz_marketoForm_pref_local = { sync_profiles: {}, - "marketo munckin": "360-KCI-804", - "marketo host": "engage.adobe.com", - "form id": "3131", + 'marketo munckin': '360-KCI-804', + 'marketo host': 'engage.adobe.com', + 'form id': '3131', form: { - template: "flex_event", + template: 'flex_event', success: { - type: "adobe_connect", - content: "https://livekitqe.dev.adobeconnect.com/paxlkm0gwsj4", + type: 'adobe_connect', + content: 'https://livekitqe.dev.adobeconnect.com/paxlkm0gwsj4', delay: 5000, confirm: false, }, - baseSite: "https://business.adobe.com", + baseSite: 'https://business.adobe.com', id: 3131, }, program: { campaignids: { - sfdc: "7015Y000004BWOnQAO", - external: "", - retouch: "", - onsite: "", - cgen: "", - cuid: "", + sfdc: '7015Y000004BWOnQAO', + external: '', + retouch: '', + onsite: '', + cgen: '', + cuid: '', }, - poi: "MARKETOENGAGEMENTPLATFORM", - additional_form_id: "", - copartnernames: "", + poi: 'MARKETOENGAGEMENTPLATFORM', + additional_form_id: '', + copartnernames: '', marketo_asset: { - name: "", - id: "", + name: '', + id: '', }, event: { - type: "adobe_connect", //connect_recording or video - subtype: "flex_event", - id: "mcz114328", + type: 'adobe_connect', // connect_recording or video + subtype: 'flex_event', + id: 'mcz114328', status: { viewport: { width: 1024, @@ -136,15 +135,15 @@ if ( audio: true, }, activity: { - start: "2025-06-07-10:00", - end: "2025-06-07-10:00", + start: '2025-06-07-10:00', + end: '2025-06-07-10:00', duration_ticks: 1000, active_ticks: 1000, log: [ { - type: "adobe_connect", - subtype: "flex_event", - id: "ACTEST4242", + type: 'adobe_connect', + subtype: 'flex_event', + id: 'ACTEST4242', }, ], }, @@ -152,39 +151,39 @@ if ( }, }, status: { - label: "invited", - milestone: "responded", - is: "1001", - dateTime: "2025-06-07-10:00", + label: 'invited', + milestone: 'responded', + is: '1001', + dateTime: '2025-06-07-10:00', }, status_previous: { - label: "invited", - milestone: "responded", - is: "1001", - dateTime: "2025-06-07-10:00", + label: 'invited', + milestone: 'responded', + is: '1001', + dateTime: '2025-06-07-10:00', }, }, field_visibility: { - name: "required", - phone: "hidden", - company: "visible", - website: "hidden", - state: "hidden", - postcode: "hidden", + name: 'required', + phone: 'hidden', + company: 'visible', + website: 'hidden', + state: 'hidden', + postcode: 'hidden', }, field_filters: { - functional_area: "Functional Area-DX", - products: "hidden", - industry: "hidden", - job_role: "hidden", - comments: "hidden", - demo: "hidden", + functional_area: 'Functional Area-DX', + products: 'hidden', + industry: 'hidden', + job_role: 'hidden', + comments: 'hidden', + demo: 'hidden', }, }; if (use_marketoConfiguratorLink) { - for (let key in marketoConfiguratorJSON) { - let keyArray = key.split("."); + for (const key in marketoConfiguratorJSON) { + const keyArray = key.split('.'); let obj = mcz_marketoForm_pref_local; for (let i = 0; i < keyArray.length - 1; i++) { if (!obj[keyArray[i]]) { @@ -196,59 +195,58 @@ if ( } } - if (!window.location.search.includes("preview=1")) { - history.pushState({}, "", `${window.location.pathname}?preview=1`); + if (!window.location.search.includes('preview=1')) { + history.pushState({}, '', `${window.location.pathname}?preview=1`); } window.mcz_marketoForm_pref = JSON.parse(JSON.stringify(mcz_marketoForm_pref_local)); - var loadScript = (url, type, { mode } = {}) => - new Promise((resolve, reject) => { - let script = document.querySelector(`head > script[src="${url}"]`); - if (!script) { - const { head } = document; - script = document.createElement("script"); - script.setAttribute("src", url); - if (type) { - script.setAttribute("type", type); - } - if (["async", "defer"].includes(mode)) script.setAttribute(mode, true); - head.append(script); + const loadScript = (url, type, { mode } = {}) => new Promise((resolve, reject) => { + let script = document.querySelector(`head > script[src="${url}"]`); + if (!script) { + const { head } = document; + script = document.createElement('script'); + script.setAttribute('src', url); + if (type) { + script.setAttribute('type', type); } + if (['async', 'defer'].includes(mode)) script.setAttribute(mode, true); + head.append(script); + } - if (script.dataset.loaded) { - resolve(script); - return; - } + if (script.dataset.loaded) { + resolve(script); + return; + } - const onScript = (event) => { - script.removeEventListener("load", onScript); - script.removeEventListener("error", onScript); + const onScript = (event) => { + script.removeEventListener('load', onScript); + script.removeEventListener('error', onScript); - if (event.type === "error") { - reject(new Error(`error loading script: ${script.src}`)); - } else if (event.type === "load") { - script.dataset.loaded = true; - resolve(script); - } - }; + if (event.type === 'error') { + reject(new Error(`error loading script: ${script.src}`)); + } else if (event.type === 'load') { + script.dataset.loaded = true; + resolve(script); + } + }; - script.addEventListener("load", onScript); - script.addEventListener("error", onScript); - }); + script.addEventListener('load', onScript); + script.addEventListener('error', onScript); + }); - const resourceForm = document.createElement("div"); + const resourceForm = document.createElement('div'); resourceForm.innerHTML = resourceFormHTML; if (document.querySelector(resourceLocation)) { document.querySelector(resourceLocation).appendChild(resourceForm); } else { - console.log("resourceLocation not found", resourceLocation); + console.log('resourceLocation not found', resourceLocation); } loadScript(`${BASE_URL}/js/forms2/js/forms2.min.js`) .then(() => { const { MktoForms2 } = window; - if (!MktoForms2) throw new Error("Marketo forms not loaded"); + if (!MktoForms2) throw new Error('Marketo forms not loaded'); MktoForms2.loadForm(`${BASE_URL}`, MUNCHKIN_ID, formID); MktoForms2.whenReady((form) => { @@ -256,15 +254,15 @@ if ( }); }) .catch(() => { - console.error("Error loading Marketo form"); + console.error('Error loading Marketo form'); }); window.addMunchkin = async function ( - munchkinId = "360-KCI-804", - pageFromEventId = "", - mktToken = "" + munchkinId = '360-KCI-804', + pageFromEventId = '', + mktToken = '', ) { - loadScript(`https://munchkin.marketo.net/munchkin.js`) + loadScript('https://munchkin.marketo.net/munchkin.js') .then(() => { Munchkin.init(munchkinId, { customName: `Testing BACOM Connect UX ${pageFromEventId}`, @@ -272,27 +270,27 @@ if ( }); }) .catch(() => { - console.error("Error loading Munchkin.js"); + console.error('Error loading Munchkin.js'); }); }; mczFrm_createProgramSyncIframe(); }; - window.mcz_marketoForm_adobe_connect_event = (event_url = "") => { - let final_url = ""; - if (event_url != "") { + window.mcz_marketoForm_adobe_connect_event = (event_url = '') => { + let final_url = ''; + if (event_url != '') { final_url = event_url.trim(); } - if (document.querySelector(".marketo-form-wrapper")) { - document.querySelector(".marketo-form-wrapper").classList.add("hide"); + if (document.querySelector('.marketo-form-wrapper')) { + document.querySelector('.marketo-form-wrapper').classList.add('hide'); } if (document.querySelector('.adobe-connect button[daa-ll*="Join"]')) { document.querySelector('.adobe-connect button[daa-ll*="Join"]').click(); } - console.log("adobe_connect_event", final_url); - mczFrm_sendMessage("reg_submitted", "root.program_profile"); + console.log('adobe_connect_event', final_url); + mczFrm_sendMessage('reg_submitted', 'root.program_profile'); }; // @@ -319,36 +317,36 @@ if ( function mczFrm_currentMarketoTime() { let serverTimeOffset; - let serverTimeRaw = mcz_marketoForm_pref?.program?.marketo_asset?.time?.systemDateTime || null; + const serverTimeRaw = mcz_marketoForm_pref?.program?.marketo_asset?.time?.systemDateTime || null; try { if (serverTimeRaw) { - let serverTimeInitial = new Date(serverTimeRaw).getTime(); + const serverTimeInitial = new Date(serverTimeRaw).getTime(); if (!isNaN(serverTimeInitial)) { - let clientTimeInitial = new Date().getTime(); + const clientTimeInitial = new Date().getTime(); serverTimeOffset = serverTimeInitial - clientTimeInitial; } } else { serverTimeOffset = 0; } } catch (e) { - console.warn("Error getting server time offset", e); + console.warn('Error getting server time offset', e); serverTimeOffset = 0; } - if (typeof serverTimeOffset === "undefined") { + if (typeof serverTimeOffset === 'undefined') { return new Date(); } return new Date(new Date().getTime() + serverTimeOffset); } - var timeUntilInterval = null; + let timeUntilInterval = null; function mczFrm_updateTimeUntil() { - let base = window?.mcz_marketoForm_pref || {}; - let endDateTime = base?.program?.event?.dateTime?.pst?.dateTimeEnd || null; - let startDateTime = base?.program?.event?.dateTime?.pst?.dateTimeStart || null; - let nowDateTime = mczFrm_currentMarketoTime(); - let general_status = "pending"; + const base = window?.mcz_marketoForm_pref || {}; + const endDateTime = base?.program?.event?.dateTime?.pst?.dateTimeEnd || null; + const startDateTime = base?.program?.event?.dateTime?.pst?.dateTimeStart || null; + const nowDateTime = mczFrm_currentMarketoTime(); + let general_status = 'pending'; if (endDateTime == null || startDateTime == null || nowDateTime == null) { - console.warn("No end or now date time found for this event"); + console.warn('No end or now date time found for this event'); return null; } @@ -358,11 +356,11 @@ if ( adobe_connect_status = {}; } - let endDate = new Date(endDateTime); - let startDate = new Date(startDateTime); - let nowDate = new Date(nowDateTime); - let timeUntilEnds = mczFrm_getTimeUntil(endDate, nowDate); - let timeUntilStart = mczFrm_getTimeUntil(startDate, nowDate); + const endDate = new Date(endDateTime); + const startDate = new Date(startDateTime); + const nowDate = new Date(nowDateTime); + const timeUntilEnds = mczFrm_getTimeUntil(endDate, nowDate); + const timeUntilStart = mczFrm_getTimeUntil(startDate, nowDate); let stillReview = true; @@ -380,7 +378,7 @@ if ( adobe_connect_status.has_started = false; adobe_connect_status.is_reg_open = false; adobe_connect_status.is_reg_closed = false; - general_status = "register"; + general_status = 'register'; if (timeUntilInterval) { clearInterval(timeUntilInterval); @@ -399,15 +397,15 @@ if ( } } - let duration = mczFrm_getTimeUntil(endDate, startDate); + const duration = mczFrm_getTimeUntil(endDate, startDate); base.program.event.dateTime.duration = duration; - let remaining = mczFrm_getTimeUntil(endDate, nowDate); + const remaining = mczFrm_getTimeUntil(endDate, nowDate); base.program.event.dateTime.remaining = remaining; // Calculate halfway point using total milliseconds for accuracy if (duration?.timeUntil > 0 && stillReview) { - let half_duration_ms = duration.timeUntil / 2; + const half_duration_ms = duration.timeUntil / 2; if (remaining?.timeUntil <= half_duration_ms && remaining?.timeUntil > 0) { adobe_connect_status.is_halfway_through = true; } @@ -418,12 +416,12 @@ if ( adobe_connect_status.about_to_end = true; } - //check if finished + // check if finished if ( - adobe_connect_status.has_started && - remaining?.timeUntil > 0 && - remaining.minutes <= 2 && - stillReview + adobe_connect_status.has_started + && remaining?.timeUntil > 0 + && remaining.minutes <= 2 + && stillReview ) { adobe_connect_status.has_ended = true; adobe_connect_status.has_finished = true; @@ -433,15 +431,15 @@ if ( adobe_connect_status.can_attend = false; adobe_connect_status.can_register = false; adobe_connect_status.has_started = true; - general_status = "finished"; + general_status = 'finished'; stillReview = false; } - //open_minutes and close_minutes - let open_minutes = base?.program?.event?.dateTime?.pst?.open_minutes || 10; //you can join 10 minutes before the event starts - let close_minutes = base?.program?.event?.dateTime?.pst?.close_minutes || 999; //you can join 999 minutes after the event starts + // open_minutes and close_minutes + const open_minutes = base?.program?.event?.dateTime?.pst?.open_minutes || 10; // you can join 10 minutes before the event starts + const close_minutes = base?.program?.event?.dateTime?.pst?.close_minutes || 999; // you can join 999 minutes after the event starts - //workout if the event is open or closed + // workout if the event is open or closed let doorsOpen = false; if (timeUntilStart?.minutes > 0 && stillReview) { if (timeUntilStart?.minutes <= open_minutes) { @@ -453,7 +451,7 @@ if ( adobe_connect_status.has_ended = false; adobe_connect_status.is_reg_open = true; adobe_connect_status.is_reg_closed = false; - general_status = "live"; + general_status = 'live'; stillReview = false; } } @@ -466,7 +464,7 @@ if ( adobe_connect_status.has_started = true; adobe_connect_status.is_reg_open = false; adobe_connect_status.is_reg_closed = true; - general_status = "live"; + general_status = 'live'; stillReview = false; } } @@ -479,37 +477,34 @@ if ( base.program.event.status = general_status; base.program.event.id = window?.programId || null; - console.log("timeUntilStart", timeUntilStart); + console.log('timeUntilStart', timeUntilStart); if (timeUntilStart.minutes <= 30) { if (!timeUntilInterval) { timeUntilInterval = setInterval(mczFrm_updateTimeUntil, 1000); } - } else { - if (timeUntilInterval) { - clearInterval(timeUntilInterval); - timeUntilInterval = null; - } + } else if (timeUntilInterval) { + clearInterval(timeUntilInterval); + timeUntilInterval = null; } } - function mczFrm_ACE_confirmURL(url_name = "", url = "") { + function mczFrm_ACE_confirmURL(url_name = '', url = '') { try { - let confirmLocation = - window.mcz_marketoForm_pref?.program?.event?.adobe_connect?.urls?.[url_name] || null; + const confirmLocation = window.mcz_marketoForm_pref?.program?.event?.adobe_connect?.urls?.[url_name] || null; if (confirmLocation == null) { return false; } - let current_status = confirmLocation?.valid_url || false; + const current_status = confirmLocation?.valid_url || false; if (current_status) { return true; } - if (url.trim() == "") { - //get the url from the config and we will validate it. - url = confirmLocation.url || ""; - if (url.trim() == "") { + if (url.trim() == '') { + // get the url from the config and we will validate it. + url = confirmLocation.url || ''; + if (url.trim() == '') { return false; } } @@ -522,7 +517,7 @@ if ( } catch (e) { confirmLocation.valid_url = false; confirmLocation.url_obj = {}; - confirmLocation.url = ""; + confirmLocation.url = ''; return false; } return true; @@ -536,19 +531,19 @@ if ( //* Communication frunctions //* async function mczFrm_createProgramSyncIframe() { - let mktToken = window.getMktToken; - let pageFromEventId = mcz_marketoForm_pref.program.event.id || ""; - if (pageFromEventId == "") { - console.log("No event id found, skipping profile sync iframe."); + const mktToken = window.getMktToken; + const pageFromEventId = mcz_marketoForm_pref.program.event.id || ''; + if (pageFromEventId == '') { + console.log('No event id found, skipping profile sync iframe.'); return; } - let munchkinId = MUNCHKIN_ID || "360-KCI-804"; + const munchkinId = MUNCHKIN_ID || '360-KCI-804'; addMunchkin(munchkinId, pageFromEventId, mktToken); - let programIDOnly = pageFromEventId.replace(/[^0-9]/g, ""); - let programfromStorage = await mczFrm_aquireFromStorage(`ev__${programIDOnly}`); + const programIDOnly = pageFromEventId.replace(/[^0-9]/g, ''); + const programfromStorage = await mczFrm_aquireFromStorage(`ev__${programIDOnly}`); if (programfromStorage) { - console.log("MCZ Form, Updating DL from storage:", programfromStorage); + console.log('MCZ Form, Updating DL from storage:', programfromStorage); mczFrm_updateDL(programfromStorage); } @@ -557,13 +552,13 @@ if ( baseURL = `${baseURL}?mkt_tok=${mktToken}`; } - const iframe = document.createElement("iframe"); - iframe.sandbox = "allow-scripts allow-same-origin"; + const iframe = document.createElement('iframe'); + iframe.sandbox = 'allow-scripts allow-same-origin'; iframe.src = baseURL; - iframe.style.display = "none"; - iframe.id = "mcz-marketo-program-iframe"; + iframe.style.display = 'none'; + iframe.id = 'mcz-marketo-program-iframe'; document.body.appendChild(iframe); - console.log("Profile sync iframe added with URL:", iframe.src); + console.log('Profile sync iframe added with URL:', iframe.src); } function mczFrm_aquireFromStorage(lookupKey = null) { @@ -598,23 +593,23 @@ if ( async function mczFrm_saveRefs(baseAlias = null, refStorageKey = null) { if (!refStorageKey) { - console.warn("No reference storage key found"); + console.warn('No reference storage key found'); return; } let existingRefs = []; - let newRefs = []; + const newRefs = []; try { - existingRefs = JSON.parse(localStorage.getItem(refStorageKey) || "[]"); + existingRefs = JSON.parse(localStorage.getItem(refStorageKey) || '[]'); } catch (e) { - console.warn("Error parsing refStorage", e); + console.warn('Error parsing refStorage', e); existingRefs = []; } const dataProfileKeys = existingRefs || []; const now = new Date().getTime(); - for (let key of dataProfileKeys) { + for (const key of dataProfileKeys) { const lookupKey = key; let itemStr = null; itemStr = sessionStorage.getItem(lookupKey); @@ -646,22 +641,22 @@ if ( } if ( - baseAlias != null && - newRefs.indexOf(baseAlias) == -1 && - existingRefs.indexOf(baseAlias) == -1 + baseAlias != null + && newRefs.indexOf(baseAlias) == -1 + && existingRefs.indexOf(baseAlias) == -1 ) { newRefs.push(baseAlias); } localStorage.setItem(refStorageKey, JSON.stringify(newRefs)); - console.log("MCZ RefData: Updated refs in refStorage", newRefs); + console.log('MCZ RefData: Updated refs in refStorage', newRefs); } async function mczFrm_saveMsg(message) { try { const saveAlias = message?.alias || null; const refStorageKey = message?.refStorage || null; - const location = message?.location || "local"; + const location = message?.location || 'local'; const dataStr = JSON.stringify(message); const sizeInBytes = new Blob([dataStr]).size; const sizeInMB = sizeInBytes / (1024 * 1024); @@ -670,11 +665,11 @@ if ( console.warn(`MCZ RefData: Large data size (${sizeInMB.toFixed(2)}MB)`); } if (!saveAlias) { - console.warn("No save alias found"); + console.warn('No save alias found'); return; } - if (location == "session") { + if (location == 'session') { sessionStorage.setItem(saveAlias, dataStr); } else { localStorage.setItem(saveAlias, dataStr); @@ -682,36 +677,34 @@ if ( mczFrm_saveRefs(saveAlias, refStorageKey); } catch (storageError) { - console.warn("Storage error:", storageError); + console.warn('Storage error:', storageError); } } - window.addEventListener("message", (event) => { - let config = { - allowedOrigins: ["https://engage.adobe.com", "https://business.adobe.com"], - }; - let eventOrigin = new URL(event.origin); + window.addEventListener('message', (event) => { + const config = { allowedOrigins: ['https://engage.adobe.com', 'https://business.adobe.com'] }; + const eventOrigin = new URL(event.origin); let allowedToPass = false; for (let i = 0; i < config.allowedOrigins.length; i++) { - let allowedOriginURL = new URL(config.allowedOrigins[i]); + const allowedOriginURL = new URL(config.allowedOrigins[i]); if ( - eventOrigin.host === allowedOriginURL.host && - eventOrigin.protocol === allowedOriginURL.protocol && - eventOrigin.port === allowedOriginURL.port + eventOrigin.host === allowedOriginURL.host + && eventOrigin.protocol === allowedOriginURL.protocol + && eventOrigin.port === allowedOriginURL.port ) { allowedToPass = true; break; } } - if (event.data && event?.data?.type !== "mcz_marketoForm_pref_sync") { + if (event.data && event?.data?.type !== 'mcz_marketoForm_pref_sync') { allowedToPass = false; } if (!allowedToPass) { return; } - console.log("MCZ RefData Received:", event.data); + console.log('MCZ RefData Received:', event.data); if (event.data && event?.data?.target_path !== null && event?.data?.target_attribute !== null) { - let save = event?.data?.save || false; + const save = event?.data?.save || false; mczFrm_updateDL(event?.data); if (save) { mczFrm_saveMsg(event?.data); @@ -723,82 +716,81 @@ if ( if (data == null) { return; } - let targetPath = data?.target_path || null; + const targetPath = data?.target_path || null; if (targetPath == null) { return; } - let program_type = data?.data?.program?.type || "default"; - let program_status = "default"; + let program_type = data?.data?.program?.type || 'default'; + let program_status = 'default'; - let this_data = JSON.parse(JSON.stringify(data?.data)); - if (targetPath == "root.program_profile") { + const this_data = JSON.parse(JSON.stringify(data?.data)); + if (targetPath == 'root.program_profile') { window.mcz_marketoForm_pref.program_profile = this_data; - } else if (targetPath == "root.profile") { + } else if (targetPath == 'root.profile') { window.mcz_marketoForm_pref.profile = this_data; - } else if (targetPath == "root.form") { + } else if (targetPath == 'root.form') { window.mcz_marketoForm_pref.form = this_data; - } else if (targetPath == "root.profile.acc") { + } else if (targetPath == 'root.profile.acc') { window.mcz_marketoForm_pref.profile.acc = this_data; - } else if (targetPath == "root.program") { + } else if (targetPath == 'root.program') { window.mcz_marketoForm_pref.program = this_data; - program_type = this_data?.type || "default"; - } else if (targetPath == "root.program.event") { + program_type = this_data?.type || 'default'; + } else if (targetPath == 'root.program.event') { window.mcz_marketoForm_pref.program.event = this_data; - program_type = this_data?.type || "default"; + program_type = this_data?.type || 'default'; } - if (window.mcz_marketoForm_pref?.program?.type == "event") { + if (window.mcz_marketoForm_pref?.program?.type == 'event') { mczFrm_updateTimeUntil(); - if (window.mcz_marketoForm_pref?.program?.event?.type == "adobe_connect") { - program_type = "adobe_connect"; - program_status = - window.mcz_marketoForm_pref?.program?.event?.adobe_connect?.status?.overall || "default"; + if (window.mcz_marketoForm_pref?.program?.event?.type == 'adobe_connect') { + program_type = 'adobe_connect'; + program_status = window.mcz_marketoForm_pref?.program?.event?.adobe_connect?.status?.overall || 'default'; } } - function mczFrm_statusLbls(program_type = "", program_status = "") { - if (program_type == "" || program_status == "") { - console.log("No program type or status found"); + function mczFrm_statusLbls(program_type = '', program_status = '') { + if (program_type == '' || program_status == '') { + console.log('No program type or status found'); return; } - let dataLabel = "data-mcz-dl-status"; - let elements = document.querySelectorAll(`[${dataLabel}]`); - let timeNow = new Date().getTime(); + const dataLabel = 'data-mcz-dl-status'; + const elements = document.querySelectorAll(`[${dataLabel}]`); + const timeNow = new Date().getTime(); for (let i = 0; i < elements.length; i++) { - let element = elements[i]; + const element = elements[i]; element.setAttribute(`${dataLabel}-dt`, timeNow); element.setAttribute(`${dataLabel}-type`, program_type); element.setAttribute(`${dataLabel}`, program_status); } } - console.log("Status Labels:", program_type, program_status); + console.log('Status Labels:', program_type, program_status); mczFrm_statusLbls(program_type, program_status); } - function mczFrm_sendMessage(msgName = null, targetPath = "root.program", data = {}) { - let iframe = document.getElementById("mcz-marketo-program-iframe"); + function mczFrm_sendMessage(msgName = null, targetPath = 'root.program', data = {}) { + const iframe = document.getElementById('mcz-marketo-program-iframe'); if (iframe) { - let message = { - type: "mcz_marketoForm_pref_sync", + const message = { + type: 'mcz_marketoForm_pref_sync', data: { target_path: targetPath, - data: data, + data, }, }; - iframe.contentWindow.postMessage(message, "https://engage.adobe.com"); + iframe.contentWindow.postMessage(message, 'https://engage.adobe.com'); } else { - console.warn("No iframe found"); + console.warn('No iframe found'); } } let maxTries = 1000; - let checkResourceLocation = async () => { + const checkResourceLocation = async () => { if (maxTries <= 0) { - console.log("maxTries reached", maxTries); + console.log('maxTries reached', maxTries); return; } maxTries--; From d4b0b0d737b3c618e51ef97f0642e3102558db69 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Wed, 23 Jul 2025 16:02:55 +0530 Subject: [PATCH 60/93] minor chrono fix --- events/blocks/chrono-box/chrono-box.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/events/blocks/chrono-box/chrono-box.js b/events/blocks/chrono-box/chrono-box.js index b4c88298..1e655ffd 100644 --- a/events/blocks/chrono-box/chrono-box.js +++ b/events/blocks/chrono-box/chrono-box.js @@ -1,5 +1,5 @@ // import { metadataStore } from '../../features/timing-framework/plugins/metadata/plugin.js'; -import { readBlockConfig, LIBS, getMetadata } from '../../scripts/utils.js'; +import { readBlockConfig, LIBS, getMetadata, setMetadata } from '../../scripts/utils.js'; function buildScheduleDoubleLinkedList(entries) { if (!entries.length) return null; @@ -170,9 +170,9 @@ export default async function init(el) { el.classList.add('error'); }); }; - setMetadata('adobe-connect-url', 'https://newadmin.dev.adobeconnect.com/gbajaj?guestname=Participant&proto=true'); + // setTimeout(() => { // console.log('setting video'); // metadataStore.set('marketo-next', 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'); From 68abc10bd311ad93a6f71b24fbadafc306f062c3 Mon Sep 17 00:00:00 2001 From: ambalika91 Date: Wed, 23 Jul 2025 17:40:20 +0530 Subject: [PATCH 61/93] Add overlay decorate --- events/blocks/adobe-connect/adobe-connect.css | 134 +++++++++++++++++- events/blocks/adobe-connect/adobe-connect.js | 100 +++++++++++-- events/blocks/adobe-connect/asset/Frame.svg | 3 + events/blocks/adobe-connect/asset/Rotate.svg | 10 ++ 4 files changed, 235 insertions(+), 12 deletions(-) create mode 100644 events/blocks/adobe-connect/asset/Frame.svg create mode 100644 events/blocks/adobe-connect/asset/Rotate.svg diff --git a/events/blocks/adobe-connect/adobe-connect.css b/events/blocks/adobe-connect/adobe-connect.css index 33ed58ac..d0c84a48 100644 --- a/events/blocks/adobe-connect/adobe-connect.css +++ b/events/blocks/adobe-connect/adobe-connect.css @@ -31,4 +31,136 @@ .adobe-connect .hidden { visibility: hidden !important; opacity: 0 !important; -} \ No newline at end of file +} + +/* Overlay background */ +.iframe-overlay { + position: fixed; + top: 0; left: 0; width: 100%; height: 100%; + background: rgba(0, 0, 0, 0.85); + color: #fff; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + z-index: 9999; + font-family: inherit; + pointer-events: auto; + padding: 10px; + gap: 16px; + flex-shrink: 0; + margin : 0; +} + +/* Close button */ +.iframe-overlay .overlay-close-btn { + display: flex; + width: 22px; + height: 22px; + align-items: flex-start; + position: absolute; + right: 32px; + top: 33px; +} + +/* Heading */ +.iframe-overlay .overlay-heading { + font-weight: 700; + text-align: center; + line-height: 125%; + font-style: normal; + color: #fff; + font-size: 24px; + align-self: stretch; + margin: 0; +} + +.iframe-overlay .overlay-heading-yrs { + font-weight: 700; + text-align: center; + line-height: 125%; + font-style: normal; + color: #fff; + font-size: 24px; + align-self: stretch; + margin: 0; +} + +/* Subheading */ +.iframe-overlay .overlay-subheading { + width: 245px; + color: #FFF; + text-align: center; + font-size: 16px; + font-weight: 700; + line-height: 125%; +} + +/* Illustration */ +.iframe-overlay .overlay-illustration { + margin: 40px 0 40px 0; + display: flex; + justify-content: center; +} + +/* Best viewed in landscape */ +.iframe-overlay .overlay-landscape { + height: 22px; + align-self: stretch; + color: #FFF; + text-align: center; + font-size: 18px; + font-style: normal; + font-weight: 700; + line-height: 125%; /* 22.5px */ +} + +/* Rotate your phone message */ +.iframe-overlay .overlay-rotate-msg { + align-self: stretch; + color: #FFF; + text-align: center; + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 150%; /* 18px */ +} + +/* Continue to webinar button */ +.iframe-overlay .overlay-continue-btn { + height: 50px; + background:#3B63FB; + color: #FFF; + text-align: center; + font-size: 19px; + font-style: normal; + font-weight: 700; + padding: 12px 24px 14px 24px; + border-radius: 100px; + line-height: 24px; /* 126.316% */ + margin-top: 40px; +} + +@media only screen and (orientation: portrait) { + .iframe-overlay .overlay-heading-yrs { + display: none; + } +} + +@media only screen and (orientation: landscape){ + .iframe-overlay .overlay-heading { + display: none; + } + + .iframe-overlay .overlay-subheading { + display: none; + } + + .iframe-overlay .overlay-landscape { + display: none; + } + + .iframe-overlay .overlay-rotate-msg { + display: none; + } +} diff --git a/events/blocks/adobe-connect/adobe-connect.js b/events/blocks/adobe-connect/adobe-connect.js index 5a733ab2..5982b90a 100644 --- a/events/blocks/adobe-connect/adobe-connect.js +++ b/events/blocks/adobe-connect/adobe-connect.js @@ -37,6 +37,83 @@ function getSearchParamsFromCurrentUrl() { return searchParams; } +function createOverlay(rowBlock) { + // Show the overlay div if it exists and is hidden + if (rowBlock.classList.contains('hidden')) { + rowBlock.classList.remove('hidden'); + } + + // Overlay container + const elements = { + overlay: rowBlock.querySelector(':scope > div:nth-of-type(1)'), + heading: rowBlock.querySelector(':scope > div:nth-of-type(1) > h2:nth-of-type(1)'), + subheading: rowBlock.querySelector(':scope > div:nth-of-type(1) > p:nth-of-type(1)'), + bestViewedInLandscape: rowBlock.querySelector(':scope > div:nth-of-type(1) > p:nth-of-type(2)'), + rotateYourPhone: rowBlock.querySelector(':scope > div:nth-of-type(1) > p:nth-of-type(3)'), + youAreAllSet: rowBlock.querySelector(':scope > div:nth-of-type(1) > h2:nth-of-type(2)'), + continueBtn: rowBlock.querySelector(':scope > div:nth-of-type(1) > p:nth-of-type(4) > a'), + }; + + const overlay = rowBlock.querySelector(':scope > div:nth-of-type(1)'); + overlay.classList.add('iframe-overlay'); + + // Close button (top right) + const closeBtn = createTag( + 'img', + { + class: 'overlay-close-btn', + 'aria-label': 'Close overlay', + src: '/events/blocks/adobe-connect/asset/Frame.svg', + alt: 'Close overlay', + }, + ); + overlay.insertAdjacentElement('beforeend', closeBtn); + closeBtn.addEventListener('click', () => overlay.remove()); + + // Heading + elements.heading.classList.add('overlay-heading'); + + // subheading + elements.subheading.classList.add('overlay-subheading'); + + // Illustration (SVG) + const rotateImg = createTag('img', { + class: 'overlay-illustration', + src: '/events/blocks/adobe-connect/asset/Rotate.svg', + alt: 'Phone rotation illustration', + }); + elements.subheading.insertAdjacentElement('afterend', rotateImg); + + elements.bestViewedInLandscape.classList.add('overlay-landscape'); + elements.rotateYourPhone.classList.add('overlay-rotate-msg'); + // Message container + const messageContainer = createTag('div', { class: 'overlay-message-container' }, [elements.bestViewedInLandscape, elements.rotateYourPhone]); + rotateImg.insertAdjacentElement('afterend', messageContainer); + + elements.continueBtn.classList.add('overlay-continue-btn'); + elements.continueBtn.addEventListener('click', (event) => { + event.preventDefault(); + overlay.remove(); + }); + + // Message for landscape mode + elements.youAreAllSet.classList.add('overlay-heading-yrs'); + + return overlay; +} + +function isMobileDevice() { + return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); +} + +function isPortraitMode() { + return window.innerHeight > window.innerWidth; +} + +function shouldShowOverlay() { + return isMobileDevice() && isPortraitMode(); +} + export default async function init(el) { const h2 = el.querySelector('h2'); let url = h2?.textContent; @@ -45,6 +122,12 @@ export default async function init(el) { h2.remove(); const button = createTag('button', { class: 'hidden' }, 'Join the event', { parent: el }); + //Hide the overlay div if it exists + const overlayElem = el.querySelector(':scope > div:nth-of-type(2)'); + if (overlayElem) { + overlayElem.classList.add('hidden'); + } + button.addEventListener('click', () => { const searchParams = getSearchParamsFromCurrentUrl(); @@ -53,17 +136,12 @@ export default async function init(el) { console.log("join_url in Window", window.join_url); } url = addSearchParams(url, searchParams); - - // Create overlay - const overlay = createTag('div', { - class: 'iframe-overlay', - style: 'position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.9); display: flex; align-items: center; justify-content: center; z-index: 1000;', - }, '', { parent: el }); - - // Create loading text - createTag('div', { - style: 'font-size: 1.2em; color: #333;', - }, 'Loading event...', { parent: overlay }); + + if (overlayElem && shouldShowOverlay()) { + createOverlay(overlayElem); + } else if (overlayElem) { + overlayElem.remove(); + } // Create iframe createTag('iframe', { diff --git a/events/blocks/adobe-connect/asset/Frame.svg b/events/blocks/adobe-connect/asset/Frame.svg new file mode 100644 index 00000000..cd2b4a5e --- /dev/null +++ b/events/blocks/adobe-connect/asset/Frame.svg @@ -0,0 +1,3 @@ + + + diff --git a/events/blocks/adobe-connect/asset/Rotate.svg b/events/blocks/adobe-connect/asset/Rotate.svg new file mode 100644 index 00000000..9234467a --- /dev/null +++ b/events/blocks/adobe-connect/asset/Rotate.svg @@ -0,0 +1,10 @@ + + + + + + + + + + From a1d63c2b59451ec07a5328098452a5344b74a939 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Wed, 23 Jul 2025 17:56:24 +0530 Subject: [PATCH 62/93] updated script --- rs/360-KCI-804/images/mktoTestFormConfig.js | 1385 +++++++++++++++---- 1 file changed, 1152 insertions(+), 233 deletions(-) diff --git a/rs/360-KCI-804/images/mktoTestFormConfig.js b/rs/360-KCI-804/images/mktoTestFormConfig.js index 724e60ce..32da191c 100644 --- a/rs/360-KCI-804/images/mktoTestFormConfig.js +++ b/rs/360-KCI-804/images/mktoTestFormConfig.js @@ -3,12 +3,14 @@ // ## if ( - typeof mczFrm_mkto_testing_loader !== 'function' - && typeof mczFrm_mkto_testing_loader === 'undefined' + typeof mczFrm_mkto_testing_loader != "function" && + typeof mczFrm_mkto_testing_loader == "undefined" ) { + //* + //* async function getMktToken() { - const storageKey = 'mkt_tok'; - let mktToken = ''; + const storageKey = "mkt_tok"; + let mktToken = ""; if (window.__mktTokVal && window.__mktTokVal?.trim()?.length > 0) { return window.__mktTokVal; @@ -16,7 +18,870 @@ if ( const urlParams = new URLSearchParams(window.location.search); if (urlParams.has(storageKey)) { - mktToken = urlParams.get(storageKey); + mktToken = urlParams.get(storageKey);// ## + // ## Test Module - Just a rough test module to set the config of the form.11 + // ## + + if ( + typeof mczFrm_mkto_testing_loader != "function" && + typeof mczFrm_mkto_testing_loader == "undefined" + ) { + //* + //* + async function getMktToken() { + const storageKey = "mkt_tok"; + let mktToken = ""; + + if (window.__mktTokVal && window.__mktTokVal?.trim()?.length > 0) { + return window.__mktTokVal; + } + + const urlParams = new URLSearchParams(window.location.search); + if (urlParams.has(storageKey)) { + mktToken = urlParams.get(storageKey); + try { + sessionStorage.setItem(storageKey, mktToken); + localStorage.setItem(storageKey, mktToken); + } catch (e) { + console.warn(`Could not save ${storageKey} to storage`, e); + } + } else { + mktToken = sessionStorage.getItem(storageKey) || localStorage.getItem(storageKey) || ""; + } + + window.__mktTokVal = mktToken; + return mktToken; + } + + window.getMktToken = await getMktToken(); + + //* + //* + //* + //* + //* + //* + //* + //* + //* + + //hide Join button + + var BASE_URL = "https://engage.marketo.com"; + var MUNCHKIN_ID = "360-KCI-804"; + var resourceLocation = ".chrono-box"; + var resourceWatch = '.chrono-box'; + let mczFrm_mkto_testing_loader = () => { + let cssFast = ` + button[daa-ll="Join the event-1--"] { + visibility: hidden !important; + opacity: 0 !important; + } + `; + let cssLinkFast = document.createElement("style"); + cssLinkFast.innerHTML = cssFast; + document.head.appendChild(cssLinkFast); + + let formID = 3131; + let resourceFormHTML = ` +
+
+ + + +
+
+ `; + + const marketoCSSresource = "https://business.adobe.com/libs/blocks/marketo/marketo.css"; + + let marketoConfiguratorLink = + "eyJmb3JtLnRlbXBsYXRlIjoicmVxdWVzdF9mb3JfaW5mb3JtYXRpb24iLCJmb3JtLnN1YnR5cGUiOiJyZXF1ZXN0X2Zvcl9pbmZvcm1hdGlvbiIsInByb2dyYW0uY2FtcGFpZ25pZHMuc2ZkYyI6IjcwMTE0MDAwMDAyWFl2SUFBVyIsInByb2dyYW0ucG9pIjoiTUFSS0VUT0VOR0FHRU1FTlRQTEFURk9STSIsImZvcm0uc3VjY2Vzcy5jb250ZW50IjoiaHR0cHM6Ly9idXNpbmVzcy5hZG9iZS5jb20vcmVzb3VyY2VzL2Vib29rcy9wcm92aW5nLXRoZS1pbXBhY3Qtb2YtbWFya2V0aW5nLW9uLXJldmVudWUvdGhhbmsteW91Lmh0bWwiLCJmb3JtLnN1Y2Nlc3MudHlwZSI6IiIsInByb2dyYW0uY29udGVudC50eXBlIjoiIiwicHJvZ3JhbS5jb250ZW50LmlkIjoiIiwiZmllbGRfdmlzaWJpbGl0eS5uYW1lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBob25lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnkiOiJyZXF1aXJlZCIsImZpZWxkX3Zpc2liaWxpdHkud2Vic2l0ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5mdW5jdGlvbmFsX2FyZWEiOiJGdW5jdGlvbmFsIEFyZWEtRFgiLCJmaWVsZF92aXNpYmlsaXR5LnN0YXRlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBvc3Rjb2RlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnlfc2l6ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5wcm9kdWN0cyI6ImhpZGRlbiIsImZpZWxkX2ZpbHRlcnMuaW5kdXN0cnkiOiJoaWRkZW4iLCJmaWVsZF9maWx0ZXJzLmpvYl9yb2xlIjoiYWxsIiwiZmllbGRfdmlzaWJpbGl0eS5jb21tZW50cyI6ImhpZGRlbiIsImZpZWxkX3Zpc2liaWxpdHkuZGVtbyI6ImhpZGRlbiIsInByb2dyYW0uY29wYXJ0bmVybmFtZXMiOiIiLCJwcm9ncmFtLmNhbXBhaWduaWRzLmV4dGVybmFsIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5yZXRvdWNoIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5vbnNpdGUiOiIiLCJwcm9ncmFtLmFkZGl0aW9uYWxfZm9ybV9pZCI6IiIsImZvcm0gaWQiOiIxNzIzIiwibWFya2V0byBtdW5ja2luIjoiMzYwLUtDSS04MDQiLCJtYXJrZXRvIGhvc3QiOiJlbmdhZ2UuYWRvYmUuY29tIiwiZm9ybSB0eXBlIjoibWFya2V0b19mb3JtIn0"; + let marketoConfiguratorHTML = ` +
+ +
+
Marketo Configurator
+
+
+ `; + + const cssLink = document.createElement("link"); + cssLink.rel = "stylesheet"; + cssLink.href = marketoCSSresource; + document.head.appendChild(cssLink); + + let marketoConfiguratorJSON = {}; + try { + marketoConfiguratorJSON = JSON.parse( + decodeURIComponent(escape(window.atob(marketoConfiguratorLink))) + ); + } catch (e) { + console.error("Error parsing Marketo Configurator JSON", e); + } + + let use_marketoConfiguratorLink = false; + + let mcz_marketoForm_pref_local = { + sync_profiles: {}, + "marketo munckin": "360-KCI-804", + "marketo host": "engage.adobe.com", + "form id": "3131", + form: { + template: "flex_event", + success: { + type: "adobe_connect", + content: "https://livekitqe.dev.adobeconnect.com/paxlkm0gwsj4", + delay: 5000, + confirm: false, + }, + baseSite: "https://business.adobe.com", + id: 3131, + }, + program: { + campaignids: { + sfdc: "7015Y000004BWOnQAO", + external: "", + retouch: "", + onsite: "", + cgen: "", + cuid: "", + }, + poi: "MARKETOENGAGEMENTPLATFORM", + additional_form_id: "", + copartnernames: "", + marketo_asset: { + name: "", + id: "", + }, + event: { + type: "adobe_connect", //connect_recording or video + subtype: "flex_event", + id: "mcz114328", + status: { + viewport: { + width: 1024, + height: 768, + active: true, + audio: true, + }, + activity: { + start: "2025-06-07-10:00", + end: "2025-06-07-10:00", + duration_ticks: 1000, + active_ticks: 1000, + log: [ + { + type: "adobe_connect", + subtype: "flex_event", + id: "ACTEST4242", + }, + ], + }, + activities: [], + }, + }, + status: { + label: "invited", + milestone: "responded", + is: "1001", + dateTime: "2025-06-07-10:00", + }, + status_previous: { + label: "invited", + milestone: "responded", + is: "1001", + dateTime: "2025-06-07-10:00", + }, + }, + field_visibility: { + name: "required", + phone: "hidden", + company: "visible", + website: "hidden", + state: "hidden", + postcode: "hidden", + }, + field_filters: { + functional_area: "Functional Area-DX", + products: "hidden", + industry: "hidden", + job_role: "hidden", + comments: "hidden", + demo: "hidden", + }, + }; + + if (use_marketoConfiguratorLink) { + for (let key in marketoConfiguratorJSON) { + let keyArray = key.split("."); + let obj = mcz_marketoForm_pref_local; + for (let i = 0; i < keyArray.length - 1; i++) { + if (!obj[keyArray[i]]) { + obj[keyArray[i]] = {}; + } + obj = obj[keyArray[i]]; + } + obj[keyArray[keyArray.length - 1]] = marketoConfiguratorJSON[key]; + } + } + + if (!window.location.search.includes("preview=1")) { + history.pushState({}, "", `${window.location.pathname}?preview=1`); + } + + window.mcz_marketoForm_pref = JSON.parse(JSON.stringify(mcz_marketoForm_pref_local)); + + var loadScript = (url, type, { mode } = {}) => + new Promise((resolve, reject) => { + let script = document.querySelector(`head > script[src="${url}"]`); + if (!script) { + const { head } = document; + script = document.createElement("script"); + script.setAttribute("src", url); + if (type) { + script.setAttribute("type", type); + } + if (["async", "defer"].includes(mode)) script.setAttribute(mode, true); + head.append(script); + } + + if (script.dataset.loaded) { + resolve(script); + return; + } + + const onScript = (event) => { + script.removeEventListener("load", onScript); + script.removeEventListener("error", onScript); + + if (event.type === "error") { + reject(new Error(`error loading script: ${script.src}`)); + } else if (event.type === "load") { + script.dataset.loaded = true; + resolve(script); + } + }; + + script.addEventListener("load", onScript); + script.addEventListener("error", onScript); + }); + + const resourceForm = document.createElement("div"); + resourceForm.innerHTML = resourceFormHTML; + if (document.querySelector(resourceLocation)) { + document.querySelector(resourceLocation).appendChild(resourceForm); + } else { + console.log("resourceLocation not found", resourceLocation); + } + + loadScript(`${BASE_URL}/js/forms2/js/forms2.min.js`) + .then(() => { + const { MktoForms2 } = window; + if (!MktoForms2) throw new Error("Marketo forms not loaded"); + + MktoForms2.loadForm(`${BASE_URL}`, MUNCHKIN_ID, formID); + MktoForms2.whenReady((form) => { + console.log("Marketo Form Thinks it's Ready", form); + }); + }) + .catch(() => { + console.error("Error loading Marketo form"); + }); + + window.addMunchkin = async function ( + munchkinId = "360-KCI-804", + pageFromEventId = "", + mktToken = "" + ) { + loadScript(`https://munchkin.marketo.net/munchkin.js`) + .then(() => { + Munchkin.init(munchkinId, { + customName: `Testing BACOM Connect UX ${pageFromEventId}`, + mkt_tok: mktToken, + }); + }) + .catch(() => { + console.error("Error loading Munchkin.js"); + }); + }; + + mczFrm_createProgramSyncIframe(); + }; + + window.mcz_marketoForm_adobe_connect_event = (event_url = "") => { + let final_url = ""; + if (event_url != "") { + final_url = event_url.trim(); + } + + if (document.querySelector(".marketo-form-wrapper")) { + document.querySelector(".marketo-form-wrapper").classList.add("hide"); + } + if (document.querySelector('.adobe-connect button[daa-ll*="Join"]')) { + document.querySelector('.adobe-connect button[daa-ll*="Join"]').click(); + } + console.log("adobe_connect_event", final_url); + mczFrm_sendMessage("reg_submitted", "root.program_profile"); + }; + + // + // + // + // + // + // + + function mczFrm_getTimeUntil(targetDate, nowDate) { + const timeUntil = targetDate - nowDate; + + if (timeUntil <= 0) { + return { days: 0, hours: 0, minutes: 0, seconds: 0, timeUntil }; + } + + const days = Math.floor(timeUntil / (1000 * 60 * 60 * 24)); + const hours = Math.floor((timeUntil % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); + const minutes = Math.floor((timeUntil % (1000 * 60 * 60)) / (1000 * 60)); + const seconds = Math.floor((timeUntil % (1000 * 60)) / 1000); + + return { days, hours, minutes, seconds, timeUntil }; + } + + function mczFrm_currentMarketoTime() { + let serverTimeOffset; + let serverTimeRaw = mcz_marketoForm_pref?.program?.marketo_asset?.time?.systemDateTime || null; + try { + if (serverTimeRaw) { + let serverTimeInitial = new Date(serverTimeRaw).getTime(); + if (!isNaN(serverTimeInitial)) { + let clientTimeInitial = new Date().getTime(); + serverTimeOffset = serverTimeInitial - clientTimeInitial; + } + } else { + serverTimeOffset = 0; + } + } catch (e) { + console.warn("Error getting server time offset", e); + serverTimeOffset = 0; + } + if (typeof serverTimeOffset === "undefined") { + return new Date(); + } + return new Date(new Date().getTime() + serverTimeOffset); + } + + var timeUntilInterval = null; + function mczFrm_updateTimeUntil() { + let base = window?.mcz_marketoForm_pref || {}; + let endDateTime = base?.program?.event?.dateTime?.pst?.dateTimeEnd || null; + let startDateTime = base?.program?.event?.dateTime?.pst?.dateTimeStart || null; + let nowDateTime = mczFrm_currentMarketoTime(); + let general_status = "pending"; + if (endDateTime == null || startDateTime == null || nowDateTime == null) { + console.warn("No end or now date time found for this event"); + return null; + } + + let adobe_connect_status = base?.program?.event?.adobe_connect?.status || null; + + if (adobe_connect_status == null) { + adobe_connect_status = {}; + } + + let endDate = new Date(endDateTime); + let startDate = new Date(startDateTime); + let nowDate = new Date(nowDateTime); + let timeUntilEnds = mczFrm_getTimeUntil(endDate, nowDate); + let timeUntilStart = mczFrm_getTimeUntil(startDate, nowDate); + + let stillReview = true; + + // Reset status flags + adobe_connect_status.is_starting_soon = false; + adobe_connect_status.is_starting_in_5_minutes = false; + adobe_connect_status.is_starting_in_1_minute = false; + adobe_connect_status.is_halfway_through = false; + adobe_connect_status.about_to_end = false; + adobe_connect_status.has_ended = false; + adobe_connect_status.has_finished = false; + adobe_connect_status.can_enter = false; + adobe_connect_status.can_attend = false; + adobe_connect_status.can_register = false; + adobe_connect_status.has_started = false; + adobe_connect_status.is_reg_open = false; + adobe_connect_status.is_reg_closed = false; + general_status = "register"; + + if (timeUntilInterval) { + clearInterval(timeUntilInterval); + } + + // Set timing status flags based on time until start + if (timeUntilStart.timeUntil > 0 && stillReview) { + if (timeUntilStart.minutes <= 10) { + adobe_connect_status.is_starting_soon = true; + } + if (timeUntilStart.minutes <= 5) { + adobe_connect_status.is_starting_in_5_minutes = true; + } + if (timeUntilStart.minutes <= 1) { + adobe_connect_status.is_starting_in_1_minute = true; + } + } + + let duration = mczFrm_getTimeUntil(endDate, startDate); + base.program.event.dateTime.duration = duration; + + let remaining = mczFrm_getTimeUntil(endDate, nowDate); + base.program.event.dateTime.remaining = remaining; + + // Calculate halfway point using total milliseconds for accuracy + if (duration?.timeUntil > 0 && stillReview) { + let half_duration_ms = duration.timeUntil / 2; + if (remaining?.timeUntil <= half_duration_ms && remaining?.timeUntil > 0) { + adobe_connect_status.is_halfway_through = true; + } + } + + // Check if event is about to end + if (remaining?.timeUntil > 0 && remaining.minutes <= 10 && stillReview) { + adobe_connect_status.about_to_end = true; + } + + //check if finished + if ( + adobe_connect_status.has_started && + remaining?.timeUntil > 0 && + remaining.minutes <= 2 && + stillReview + ) { + adobe_connect_status.has_ended = true; + adobe_connect_status.has_finished = true; + adobe_connect_status.is_reg_open = false; + adobe_connect_status.is_reg_closed = true; + adobe_connect_status.can_enter = false; + adobe_connect_status.can_attend = false; + adobe_connect_status.can_register = false; + adobe_connect_status.has_started = true; + general_status = "finished"; + stillReview = false; + } + + //open_minutes and close_minutes + let open_minutes = base?.program?.event?.dateTime?.pst?.open_minutes || 10; //you can join 10 minutes before the event starts + let close_minutes = base?.program?.event?.dateTime?.pst?.close_minutes || 999; //you can join 999 minutes after the event starts + + //workout if the event is open or closed + let doorsOpen = false; + if (timeUntilStart?.minutes > 0 && stillReview) { + if (timeUntilStart?.minutes <= open_minutes) { + doorsOpen = true; + adobe_connect_status.can_enter = true; + adobe_connect_status.can_attend = true; + adobe_connect_status.can_register = true; + adobe_connect_status.has_started = true; + adobe_connect_status.has_ended = false; + adobe_connect_status.is_reg_open = true; + adobe_connect_status.is_reg_closed = false; + general_status = "live"; + stillReview = false; + } + } + if (doorsOpen) { + if (duration?.minutes >= close_minutes && stillReview) { + doorsOpen = false; + adobe_connect_status.can_enter = false; + adobe_connect_status.can_attend = false; + adobe_connect_status.can_register = false; + adobe_connect_status.has_started = true; + adobe_connect_status.is_reg_open = false; + adobe_connect_status.is_reg_closed = true; + general_status = "live"; + stillReview = false; + } + } + + base.program.event.dateTime.timeUntil = { + starts: timeUntilStart, + ends: timeUntilEnds, + }; + adobe_connect_status.overall = general_status; + base.program.event.status = general_status; + base.program.event.id = window?.programId || null; + + console.log("timeUntilStart", timeUntilStart); + + if (timeUntilStart.minutes <= 30) { + if (!timeUntilInterval) { + timeUntilInterval = setInterval(mczFrm_updateTimeUntil, 1000); + } + } else { + if (timeUntilInterval) { + clearInterval(timeUntilInterval); + timeUntilInterval = null; + } + } + } + + function mczFrm_ACE_confirmURL(url_name = "", url = "") { + try { + let confirmLocation = + window.mcz_marketoForm_pref?.program?.event?.adobe_connect?.urls?.[url_name] || null; + if (confirmLocation == null) { + return false; + } + + let current_status = confirmLocation?.valid_url || false; + if (current_status) { + return true; + } + + if (url.trim() == "") { + //get the url from the config and we will validate it. + url = confirmLocation.url || ""; + if (url.trim() == "") { + return false; + } + } + + confirmLocation.url = url; + + try { + confirmLocation.url_obj = new URL(url); + confirmLocation.valid_url = true; + } catch (e) { + confirmLocation.valid_url = false; + confirmLocation.url_obj = {}; + confirmLocation.url = ""; + return false; + } + return true; + } catch (e) { + return false; + } + } + //* + //* + //* + //* Communication frunctions + //* + async function mczFrm_createProgramSyncIframe() { + let mktToken = window.getMktToken; + let pageFromEventId = mcz_marketoForm_pref.program.event.id || ""; + if (pageFromEventId == "") { + console.log("No event id found, skipping profile sync iframe."); + return; + } + + let munchkinId = MUNCHKIN_ID || "360-KCI-804"; + addMunchkin(munchkinId, pageFromEventId, mktToken); + let programIDOnly = pageFromEventId.replace(/[^0-9]/g, ""); + let programfromStorage = await mczFrm_aquireFromStorage(`ev__${programIDOnly}`); + if (programfromStorage) { + console.log("MCZ Form, Updating DL from storage:", programfromStorage); + mczFrm_updateDL(programfromStorage); + } + + let baseURL = `https://engage.adobe.com/${pageFromEventId}.html`; + if (mktToken) { + baseURL = `${baseURL}?mkt_tok=${mktToken}`; + } + + const iframe = document.createElement("iframe"); + iframe.sandbox = "allow-scripts allow-same-origin"; + iframe.src = baseURL; + iframe.style.display = "none"; + iframe.id = "mcz-marketo-program-iframe"; + document.body.appendChild(iframe); + console.log("Profile sync iframe added with URL:", iframe.src); + } + + function mczFrm_aquireFromStorage(lookupKey = null) { + const now = new Date().getTime(); + + let itemStr = null; + itemStr = sessionStorage.getItem(lookupKey); + if (!itemStr) { + itemStr = localStorage.getItem(lookupKey); + } + if (!itemStr) { + return null; + } + + try { + const item = JSON.parse(itemStr); + const shelfLife = item?.shelf_life || 0; + const timestamp = item?.timestamp || 0; + const expires = item?.expires || 0; + + if (now - timestamp > shelfLife || now > expires) { + sessionStorage.removeItem(lookupKey); + localStorage.removeItem(lookupKey); + console.log(`MCZ RefData: Expired program removed from ${lookupKey}`); + return null; + } + return item; + } catch (e) { + return null; + } + } + + async function mczFrm_saveRefs(baseAlias = null, refStorageKey = null) { + if (!refStorageKey) { + console.warn("No reference storage key found"); + return; + } + + let existingRefs = []; + let newRefs = []; + try { + existingRefs = JSON.parse(localStorage.getItem(refStorageKey) || "[]"); + } catch (e) { + console.warn("Error parsing refStorage", e); + existingRefs = []; + } + + const dataProfileKeys = existingRefs || []; + const now = new Date().getTime(); + + for (let key of dataProfileKeys) { + const lookupKey = key; + let itemStr = null; + itemStr = sessionStorage.getItem(lookupKey); + if (!itemStr) { + itemStr = localStorage.getItem(lookupKey); + } + if (!itemStr) { + continue; + } + + try { + const item = JSON.parse(itemStr); + const shelfLife = item?.shelf_life || 0; + const timestamp = item?.timestamp || 0; + const expires = item?.expires || 0; + + if (now - timestamp > shelfLife || now > expires) { + sessionStorage.removeItem(lookupKey); + localStorage.removeItem(lookupKey); + console.log(`MCZ RefData: Expired ref removed from ${lookupKey}`); + } else { + newRefs.push(lookupKey); + } + } catch (e) { + console.warn(`Error parsing dataProfile for key: ${lookupKey}`, e); + sessionStorage.removeItem(lookupKey); + localStorage.removeItem(lookupKey); + } + } + + if ( + baseAlias != null && + newRefs.indexOf(baseAlias) == -1 && + existingRefs.indexOf(baseAlias) == -1 + ) { + newRefs.push(baseAlias); + } + + localStorage.setItem(refStorageKey, JSON.stringify(newRefs)); + console.log("MCZ RefData: Updated refs in refStorage", newRefs); + } + + async function mczFrm_saveMsg(message) { + try { + const saveAlias = message?.alias || null; + const refStorageKey = message?.refStorage || null; + const location = message?.location || "local"; + const dataStr = JSON.stringify(message); + const sizeInBytes = new Blob([dataStr]).size; + const sizeInMB = sizeInBytes / (1024 * 1024); + + if (sizeInMB > 2) { + console.warn(`MCZ RefData: Large data size (${sizeInMB.toFixed(2)}MB)`); + } + if (!saveAlias) { + console.warn("No save alias found"); + return; + } + + if (location == "session") { + sessionStorage.setItem(saveAlias, dataStr); + } else { + localStorage.setItem(saveAlias, dataStr); + } + + mczFrm_saveRefs(saveAlias, refStorageKey); + } catch (storageError) { + console.warn("Storage error:", storageError); + } + } + + window.addEventListener("message", (event) => { + let config = { + allowedOrigins: ["https://engage.adobe.com", "https://business.adobe.com"], + }; + let eventOrigin = new URL(event.origin); + let allowedToPass = false; + for (let i = 0; i < config.allowedOrigins.length; i++) { + let allowedOriginURL = new URL(config.allowedOrigins[i]); + if ( + eventOrigin.host === allowedOriginURL.host && + eventOrigin.protocol === allowedOriginURL.protocol && + eventOrigin.port === allowedOriginURL.port + ) { + allowedToPass = true; + break; + } + } + if (event.data && event?.data?.type !== "mcz_marketoForm_pref_sync") { + allowedToPass = false; + } + if (!allowedToPass) { + return; + } + console.log("MCZ RefData Received:", event.data); + if (event.data && event?.data?.target_path !== null && event?.data?.target_attribute !== null) { + let save = event?.data?.save || false; + mczFrm_updateDL(event?.data); + if (save) { + mczFrm_saveMsg(event?.data); + } + } + }); + + function mczFrm_updateDL(data = null) { + if (data == null) { + return; + } + let targetPath = data?.target_path || null; + if (targetPath == null) { + return; + } + let program_type = data?.data?.program?.type || "default"; + let program_status = "default"; + + let this_data = JSON.parse(JSON.stringify(data?.data)); + if (targetPath == "root.program_profile") { + window.mcz_marketoForm_pref.program_profile = this_data; + } else if (targetPath == "root.profile") { + window.mcz_marketoForm_pref.profile = this_data; + } else if (targetPath == "root.form") { + window.mcz_marketoForm_pref.form = this_data; + } else if (targetPath == "root.profile.acc") { + window.mcz_marketoForm_pref.profile.acc = this_data; + } else if (targetPath == "root.program") { + window.mcz_marketoForm_pref.program = this_data; + program_type = this_data?.type || "default"; + } else if (targetPath == "root.program.event") { + window.mcz_marketoForm_pref.program.event = this_data; + program_type = this_data?.type || "default"; + } + + if (window.mcz_marketoForm_pref?.program?.type == "event") { + mczFrm_updateTimeUntil(); + if (window.mcz_marketoForm_pref?.program?.event?.type == "adobe_connect") { + program_type = "adobe_connect"; + program_status = + window.mcz_marketoForm_pref?.program?.event?.adobe_connect?.status?.overall || "default"; + } + } + + function mczFrm_statusLbls(program_type = "", program_status = "") { + if (program_type == "" || program_status == "") { + console.log("No program type or status found"); + return; + } + + let dataLabel = "data-mcz-dl-status"; + let elements = document.querySelectorAll(`[${dataLabel}]`); + let timeNow = new Date().getTime(); + for (let i = 0; i < elements.length; i++) { + let element = elements[i]; + element.setAttribute(`${dataLabel}-dt`, timeNow); + element.setAttribute(`${dataLabel}-type`, program_type); + element.setAttribute(`${dataLabel}`, program_status); + } + } + + console.log("Status Labels:", program_type, program_status); + + mczFrm_statusLbls(program_type, program_status); + } + + function mczFrm_sendMessage(msgName = null, targetPath = "root.program", data = {}) { + let iframe = document.getElementById("mcz-marketo-program-iframe"); + if (iframe) { + let message = { + type: "mcz_marketoForm_pref_sync", + data: { + target_path: targetPath, + data: data, + }, + }; + + iframe.contentWindow.postMessage(message, "https://engage.adobe.com"); + } else { + console.warn("No iframe found"); + } + } + + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + let maxTries = 1000; + let checkResourceLocation = async () => { + if (maxTries <= 0) { + console.log("maxTries reached", maxTries); + return; + } + maxTries--; + if (document.querySelector(resourceWatch)) { + mczFrm_mkto_testing_loader(); + } else { + await new Promise((resolve) => setTimeout(resolve, 25)); + checkResourceLocation(); + } + }; + checkResourceLocation(); + } + + // ## + // ## try { sessionStorage.setItem(storageKey, mktToken); localStorage.setItem(storageKey, mktToken); @@ -24,7 +889,7 @@ if ( console.warn(`Could not save ${storageKey} to storage`, e); } } else { - mktToken = sessionStorage.getItem(storageKey) || localStorage.getItem(storageKey) || ''; + mktToken = sessionStorage.getItem(storageKey) || localStorage.getItem(storageKey) || ""; } window.__mktTokVal = mktToken; @@ -33,25 +898,35 @@ if ( window.getMktToken = await getMktToken(); - // hide Join button + //* + //* + //* + //* + //* + //* + //* + //* + //* + + //hide Join button - const BASE_URL = 'https://engage.marketo.com'; - const MUNCHKIN_ID = '360-KCI-804'; - const resourceLocation = '.chrono-box'; - const resourceWatch = '.chrono-box'; - const mczFrm_mkto_testing_loader = () => { - const cssFast = ` + var BASE_URL = "https://engage.marketo.com"; + var MUNCHKIN_ID = "360-KCI-804"; + var resourceLocation = ".chrono-box"; + var resourceWatch = '.chrono-box'; + let mczFrm_mkto_testing_loader = () => { + let cssFast = ` button[daa-ll="Join the event-1--"] { visibility: hidden !important; opacity: 0 !important; } `; - const cssLinkFast = document.createElement('style'); + let cssLinkFast = document.createElement("style"); cssLinkFast.innerHTML = cssFast; document.head.appendChild(cssLinkFast); - const formID = 3131; - const resourceFormHTML = ` + let formID = 3131; + let resourceFormHTML = `
@@ -61,10 +936,11 @@ if (
`; - const marketoCSSresource = 'https://business.adobe.com/libs/blocks/marketo/marketo.css'; + const marketoCSSresource = "https://business.adobe.com/libs/blocks/marketo/marketo.css"; - const marketoConfiguratorLink = 'eyJmb3JtLnRlbXBsYXRlIjoicmVxdWVzdF9mb3JfaW5mb3JtYXRpb24iLCJmb3JtLnN1YnR5cGUiOiJyZXF1ZXN0X2Zvcl9pbmZvcm1hdGlvbiIsInByb2dyYW0uY2FtcGFpZ25pZHMuc2ZkYyI6IjcwMTE0MDAwMDAyWFl2SUFBVyIsInByb2dyYW0ucG9pIjoiTUFSS0VUT0VOR0FHRU1FTlRQTEFURk9STSIsImZvcm0uc3VjY2Vzcy5jb250ZW50IjoiaHR0cHM6Ly9idXNpbmVzcy5hZG9iZS5jb20vcmVzb3VyY2VzL2Vib29rcy9wcm92aW5nLXRoZS1pbXBhY3Qtb2YtbWFya2V0aW5nLW9uLXJldmVudWUvdGhhbmsteW91Lmh0bWwiLCJmb3JtLnN1Y2Nlc3MudHlwZSI6IiIsInByb2dyYW0uY29udGVudC50eXBlIjoiIiwicHJvZ3JhbS5jb250ZW50LmlkIjoiIiwiZmllbGRfdmlzaWJpbGl0eS5uYW1lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBob25lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnkiOiJyZXF1aXJlZCIsImZpZWxkX3Zpc2liaWxpdHkud2Vic2l0ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5mdW5jdGlvbmFsX2FyZWEiOiJGdW5jdGlvbmFsIEFyZWEtRFgiLCJmaWVsZF92aXNpYmlsaXR5LnN0YXRlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBvc3Rjb2RlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnlfc2l6ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5wcm9kdWN0cyI6ImhpZGRlbiIsImZpZWxkX2ZpbHRlcnMuaW5kdXN0cnkiOiJoaWRkZW4iLCJmaWVsZF9maWx0ZXJzLmpvYl9yb2xlIjoiYWxsIiwiZmllbGRfdmlzaWJpbGl0eS5jb21tZW50cyI6ImhpZGRlbiIsImZpZWxkX3Zpc2liaWxpdHkuZGVtbyI6ImhpZGRlbiIsInByb2dyYW0uY29wYXJ0bmVybmFtZXMiOiIiLCJwcm9ncmFtLmNhbXBhaWduaWRzLmV4dGVybmFsIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5yZXRvdWNoIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5vbnNpdGUiOiIiLCJwcm9ncmFtLmFkZGl0aW9uYWxfZm9ybV9pZCI6IiIsImZvcm0gaWQiOiIxNzIzIiwibWFya2V0byBtdW5ja2luIjoiMzYwLUtDSS04MDQiLCJtYXJrZXRvIGhvc3QiOiJlbmdhZ2UuYWRvYmUuY29tIiwiZm9ybSB0eXBlIjoibWFya2V0b19mb3JtIn0'; - const marketoConfiguratorHTML = ` + let marketoConfiguratorLink = + "eyJmb3JtLnRlbXBsYXRlIjoicmVxdWVzdF9mb3JfaW5mb3JtYXRpb24iLCJmb3JtLnN1YnR5cGUiOiJyZXF1ZXN0X2Zvcl9pbmZvcm1hdGlvbiIsInByb2dyYW0uY2FtcGFpZ25pZHMuc2ZkYyI6IjcwMTE0MDAwMDAyWFl2SUFBVyIsInByb2dyYW0ucG9pIjoiTUFSS0VUT0VOR0FHRU1FTlRQTEFURk9STSIsImZvcm0uc3VjY2Vzcy5jb250ZW50IjoiaHR0cHM6Ly9idXNpbmVzcy5hZG9iZS5jb20vcmVzb3VyY2VzL2Vib29rcy9wcm92aW5nLXRoZS1pbXBhY3Qtb2YtbWFya2V0aW5nLW9uLXJldmVudWUvdGhhbmsteW91Lmh0bWwiLCJmb3JtLnN1Y2Nlc3MudHlwZSI6IiIsInByb2dyYW0uY29udGVudC50eXBlIjoiIiwicHJvZ3JhbS5jb250ZW50LmlkIjoiIiwiZmllbGRfdmlzaWJpbGl0eS5uYW1lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBob25lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnkiOiJyZXF1aXJlZCIsImZpZWxkX3Zpc2liaWxpdHkud2Vic2l0ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5mdW5jdGlvbmFsX2FyZWEiOiJGdW5jdGlvbmFsIEFyZWEtRFgiLCJmaWVsZF92aXNpYmlsaXR5LnN0YXRlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBvc3Rjb2RlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnlfc2l6ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5wcm9kdWN0cyI6ImhpZGRlbiIsImZpZWxkX2ZpbHRlcnMuaW5kdXN0cnkiOiJoaWRkZW4iLCJmaWVsZF9maWx0ZXJzLmpvYl9yb2xlIjoiYWxsIiwiZmllbGRfdmlzaWJpbGl0eS5jb21tZW50cyI6ImhpZGRlbiIsImZpZWxkX3Zpc2liaWxpdHkuZGVtbyI6ImhpZGRlbiIsInByb2dyYW0uY29wYXJ0bmVybmFtZXMiOiIiLCJwcm9ncmFtLmNhbXBhaWduaWRzLmV4dGVybmFsIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5yZXRvdWNoIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5vbnNpdGUiOiIiLCJwcm9ncmFtLmFkZGl0aW9uYWxfZm9ybV9pZCI6IiIsImZvcm0gaWQiOiIxNzIzIiwibWFya2V0byBtdW5ja2luIjoiMzYwLUtDSS04MDQiLCJtYXJrZXRvIGhvc3QiOiJlbmdhZ2UuYWRvYmUuY29tIiwiZm9ybSB0eXBlIjoibWFya2V0b19mb3JtIn0"; + let marketoConfiguratorHTML = `
@@ -75,58 +951,58 @@ if (
`; - const cssLink = document.createElement('link'); - cssLink.rel = 'stylesheet'; + const cssLink = document.createElement("link"); + cssLink.rel = "stylesheet"; cssLink.href = marketoCSSresource; document.head.appendChild(cssLink); let marketoConfiguratorJSON = {}; try { marketoConfiguratorJSON = JSON.parse( - decodeURIComponent(escape(window.atob(marketoConfiguratorLink))), + decodeURIComponent(escape(window.atob(marketoConfiguratorLink))) ); } catch (e) { - console.error('Error parsing Marketo Configurator JSON', e); + console.error("Error parsing Marketo Configurator JSON", e); } - const use_marketoConfiguratorLink = false; + let use_marketoConfiguratorLink = false; - const mcz_marketoForm_pref_local = { + let mcz_marketoForm_pref_local = { sync_profiles: {}, - 'marketo munckin': '360-KCI-804', - 'marketo host': 'engage.adobe.com', - 'form id': '3131', + "marketo munckin": "360-KCI-804", + "marketo host": "engage.adobe.com", + "form id": "3131", form: { - template: 'flex_event', + template: "flex_event", success: { - type: 'adobe_connect', - content: 'https://livekitqe.dev.adobeconnect.com/paxlkm0gwsj4', + type: "adobe_connect", + content: "https://livekitqe.dev.adobeconnect.com/paxlkm0gwsj4", delay: 5000, confirm: false, }, - baseSite: 'https://business.adobe.com', + baseSite: "https://business.adobe.com", id: 3131, }, program: { campaignids: { - sfdc: '7015Y000004BWOnQAO', - external: '', - retouch: '', - onsite: '', - cgen: '', - cuid: '', + sfdc: "7015Y000004BWOnQAO", + external: "", + retouch: "", + onsite: "", + cgen: "", + cuid: "", }, - poi: 'MARKETOENGAGEMENTPLATFORM', - additional_form_id: '', - copartnernames: '', + poi: "MARKETOENGAGEMENTPLATFORM", + additional_form_id: "", + copartnernames: "", marketo_asset: { - name: '', - id: '', + name: "", + id: "", }, event: { - type: 'adobe_connect', // connect_recording or video - subtype: 'flex_event', - id: 'mcz114328', + type: "adobe_connect", //connect_recording or video + subtype: "flex_event", + id: "mcz114328", status: { viewport: { width: 1024, @@ -135,15 +1011,15 @@ if ( audio: true, }, activity: { - start: '2025-06-07-10:00', - end: '2025-06-07-10:00', + start: "2025-06-07-10:00", + end: "2025-06-07-10:00", duration_ticks: 1000, active_ticks: 1000, log: [ { - type: 'adobe_connect', - subtype: 'flex_event', - id: 'ACTEST4242', + type: "adobe_connect", + subtype: "flex_event", + id: "ACTEST4242", }, ], }, @@ -151,39 +1027,39 @@ if ( }, }, status: { - label: 'invited', - milestone: 'responded', - is: '1001', - dateTime: '2025-06-07-10:00', + label: "invited", + milestone: "responded", + is: "1001", + dateTime: "2025-06-07-10:00", }, status_previous: { - label: 'invited', - milestone: 'responded', - is: '1001', - dateTime: '2025-06-07-10:00', + label: "invited", + milestone: "responded", + is: "1001", + dateTime: "2025-06-07-10:00", }, }, field_visibility: { - name: 'required', - phone: 'hidden', - company: 'visible', - website: 'hidden', - state: 'hidden', - postcode: 'hidden', + name: "required", + phone: "hidden", + company: "visible", + website: "hidden", + state: "hidden", + postcode: "hidden", }, field_filters: { - functional_area: 'Functional Area-DX', - products: 'hidden', - industry: 'hidden', - job_role: 'hidden', - comments: 'hidden', - demo: 'hidden', + functional_area: "Functional Area-DX", + products: "hidden", + industry: "hidden", + job_role: "hidden", + comments: "hidden", + demo: "hidden", }, }; if (use_marketoConfiguratorLink) { - for (const key in marketoConfiguratorJSON) { - const keyArray = key.split('.'); + for (let key in marketoConfiguratorJSON) { + let keyArray = key.split("."); let obj = mcz_marketoForm_pref_local; for (let i = 0; i < keyArray.length - 1; i++) { if (!obj[keyArray[i]]) { @@ -195,58 +1071,59 @@ if ( } } - if (!window.location.search.includes('preview=1')) { - history.pushState({}, '', `${window.location.pathname}?preview=1`); + if (!window.location.search.includes("preview=1")) { + history.pushState({}, "", `${window.location.pathname}?preview=1`); } window.mcz_marketoForm_pref = JSON.parse(JSON.stringify(mcz_marketoForm_pref_local)); - const loadScript = (url, type, { mode } = {}) => new Promise((resolve, reject) => { - let script = document.querySelector(`head > script[src="${url}"]`); - if (!script) { - const { head } = document; - script = document.createElement('script'); - script.setAttribute('src', url); - if (type) { - script.setAttribute('type', type); + var loadScript = (url, type, { mode } = {}) => + new Promise((resolve, reject) => { + let script = document.querySelector(`head > script[src="${url}"]`); + if (!script) { + const { head } = document; + script = document.createElement("script"); + script.setAttribute("src", url); + if (type) { + script.setAttribute("type", type); + } + if (["async", "defer"].includes(mode)) script.setAttribute(mode, true); + head.append(script); } - if (['async', 'defer'].includes(mode)) script.setAttribute(mode, true); - head.append(script); - } - - if (script.dataset.loaded) { - resolve(script); - return; - } - const onScript = (event) => { - script.removeEventListener('load', onScript); - script.removeEventListener('error', onScript); - - if (event.type === 'error') { - reject(new Error(`error loading script: ${script.src}`)); - } else if (event.type === 'load') { - script.dataset.loaded = true; + if (script.dataset.loaded) { resolve(script); + return; } - }; - script.addEventListener('load', onScript); - script.addEventListener('error', onScript); - }); + const onScript = (event) => { + script.removeEventListener("load", onScript); + script.removeEventListener("error", onScript); + + if (event.type === "error") { + reject(new Error(`error loading script: ${script.src}`)); + } else if (event.type === "load") { + script.dataset.loaded = true; + resolve(script); + } + }; + + script.addEventListener("load", onScript); + script.addEventListener("error", onScript); + }); - const resourceForm = document.createElement('div'); + const resourceForm = document.createElement("div"); resourceForm.innerHTML = resourceFormHTML; if (document.querySelector(resourceLocation)) { document.querySelector(resourceLocation).appendChild(resourceForm); } else { - console.log('resourceLocation not found', resourceLocation); + console.log("resourceLocation not found", resourceLocation); } loadScript(`${BASE_URL}/js/forms2/js/forms2.min.js`) .then(() => { const { MktoForms2 } = window; - if (!MktoForms2) throw new Error('Marketo forms not loaded'); + if (!MktoForms2) throw new Error("Marketo forms not loaded"); MktoForms2.loadForm(`${BASE_URL}`, MUNCHKIN_ID, formID); MktoForms2.whenReady((form) => { @@ -254,15 +1131,15 @@ if ( }); }) .catch(() => { - console.error('Error loading Marketo form'); + console.error("Error loading Marketo form"); }); window.addMunchkin = async function ( - munchkinId = '360-KCI-804', - pageFromEventId = '', - mktToken = '', + munchkinId = "360-KCI-804", + pageFromEventId = "", + mktToken = "" ) { - loadScript('https://munchkin.marketo.net/munchkin.js') + loadScript(`https://munchkin.marketo.net/munchkin.js`) .then(() => { Munchkin.init(munchkinId, { customName: `Testing BACOM Connect UX ${pageFromEventId}`, @@ -270,27 +1147,27 @@ if ( }); }) .catch(() => { - console.error('Error loading Munchkin.js'); + console.error("Error loading Munchkin.js"); }); }; mczFrm_createProgramSyncIframe(); }; - window.mcz_marketoForm_adobe_connect_event = (event_url = '') => { - let final_url = ''; - if (event_url != '') { + window.mcz_marketoForm_adobe_connect_event = (event_url = "") => { + let final_url = ""; + if (event_url != "") { final_url = event_url.trim(); } - if (document.querySelector('.marketo-form-wrapper')) { - document.querySelector('.marketo-form-wrapper').classList.add('hide'); + if (document.querySelector(".marketo-form-wrapper")) { + document.querySelector(".marketo-form-wrapper").classList.add("hide"); } if (document.querySelector('.adobe-connect button[daa-ll*="Join"]')) { document.querySelector('.adobe-connect button[daa-ll*="Join"]').click(); } - console.log('adobe_connect_event', final_url); - mczFrm_sendMessage('reg_submitted', 'root.program_profile'); + console.log("adobe_connect_event", final_url); + mczFrm_sendMessage("reg_submitted", "root.program_profile"); }; // @@ -317,36 +1194,36 @@ if ( function mczFrm_currentMarketoTime() { let serverTimeOffset; - const serverTimeRaw = mcz_marketoForm_pref?.program?.marketo_asset?.time?.systemDateTime || null; + let serverTimeRaw = mcz_marketoForm_pref?.program?.marketo_asset?.time?.systemDateTime || null; try { if (serverTimeRaw) { - const serverTimeInitial = new Date(serverTimeRaw).getTime(); + let serverTimeInitial = new Date(serverTimeRaw).getTime(); if (!isNaN(serverTimeInitial)) { - const clientTimeInitial = new Date().getTime(); + let clientTimeInitial = new Date().getTime(); serverTimeOffset = serverTimeInitial - clientTimeInitial; } } else { serverTimeOffset = 0; } } catch (e) { - console.warn('Error getting server time offset', e); + console.warn("Error getting server time offset", e); serverTimeOffset = 0; } - if (typeof serverTimeOffset === 'undefined') { + if (typeof serverTimeOffset === "undefined") { return new Date(); } return new Date(new Date().getTime() + serverTimeOffset); } - let timeUntilInterval = null; + var timeUntilInterval = null; function mczFrm_updateTimeUntil() { - const base = window?.mcz_marketoForm_pref || {}; - const endDateTime = base?.program?.event?.dateTime?.pst?.dateTimeEnd || null; - const startDateTime = base?.program?.event?.dateTime?.pst?.dateTimeStart || null; - const nowDateTime = mczFrm_currentMarketoTime(); - let general_status = 'pending'; + let base = window?.mcz_marketoForm_pref || {}; + let endDateTime = base?.program?.event?.dateTime?.pst?.dateTimeEnd || null; + let startDateTime = base?.program?.event?.dateTime?.pst?.dateTimeStart || null; + let nowDateTime = mczFrm_currentMarketoTime(); + let general_status = "pending"; if (endDateTime == null || startDateTime == null || nowDateTime == null) { - console.warn('No end or now date time found for this event'); + console.warn("No end or now date time found for this event"); return null; } @@ -356,11 +1233,11 @@ if ( adobe_connect_status = {}; } - const endDate = new Date(endDateTime); - const startDate = new Date(startDateTime); - const nowDate = new Date(nowDateTime); - const timeUntilEnds = mczFrm_getTimeUntil(endDate, nowDate); - const timeUntilStart = mczFrm_getTimeUntil(startDate, nowDate); + let endDate = new Date(endDateTime); + let startDate = new Date(startDateTime); + let nowDate = new Date(nowDateTime); + let timeUntilEnds = mczFrm_getTimeUntil(endDate, nowDate); + let timeUntilStart = mczFrm_getTimeUntil(startDate, nowDate); let stillReview = true; @@ -378,7 +1255,7 @@ if ( adobe_connect_status.has_started = false; adobe_connect_status.is_reg_open = false; adobe_connect_status.is_reg_closed = false; - general_status = 'register'; + general_status = "register"; if (timeUntilInterval) { clearInterval(timeUntilInterval); @@ -397,15 +1274,15 @@ if ( } } - const duration = mczFrm_getTimeUntil(endDate, startDate); + let duration = mczFrm_getTimeUntil(endDate, startDate); base.program.event.dateTime.duration = duration; - const remaining = mczFrm_getTimeUntil(endDate, nowDate); + let remaining = mczFrm_getTimeUntil(endDate, nowDate); base.program.event.dateTime.remaining = remaining; // Calculate halfway point using total milliseconds for accuracy if (duration?.timeUntil > 0 && stillReview) { - const half_duration_ms = duration.timeUntil / 2; + let half_duration_ms = duration.timeUntil / 2; if (remaining?.timeUntil <= half_duration_ms && remaining?.timeUntil > 0) { adobe_connect_status.is_halfway_through = true; } @@ -416,12 +1293,12 @@ if ( adobe_connect_status.about_to_end = true; } - // check if finished + //check if finished if ( - adobe_connect_status.has_started - && remaining?.timeUntil > 0 - && remaining.minutes <= 2 - && stillReview + adobe_connect_status.has_started && + remaining?.timeUntil > 0 && + remaining.minutes <= 2 && + stillReview ) { adobe_connect_status.has_ended = true; adobe_connect_status.has_finished = true; @@ -431,15 +1308,15 @@ if ( adobe_connect_status.can_attend = false; adobe_connect_status.can_register = false; adobe_connect_status.has_started = true; - general_status = 'finished'; + general_status = "finished"; stillReview = false; } - // open_minutes and close_minutes - const open_minutes = base?.program?.event?.dateTime?.pst?.open_minutes || 10; // you can join 10 minutes before the event starts - const close_minutes = base?.program?.event?.dateTime?.pst?.close_minutes || 999; // you can join 999 minutes after the event starts + //open_minutes and close_minutes + let open_minutes = base?.program?.event?.dateTime?.pst?.open_minutes || 10; //you can join 10 minutes before the event starts + let close_minutes = base?.program?.event?.dateTime?.pst?.close_minutes || 999; //you can join 999 minutes after the event starts - // workout if the event is open or closed + //workout if the event is open or closed let doorsOpen = false; if (timeUntilStart?.minutes > 0 && stillReview) { if (timeUntilStart?.minutes <= open_minutes) { @@ -451,7 +1328,7 @@ if ( adobe_connect_status.has_ended = false; adobe_connect_status.is_reg_open = true; adobe_connect_status.is_reg_closed = false; - general_status = 'live'; + general_status = "live"; stillReview = false; } } @@ -464,7 +1341,7 @@ if ( adobe_connect_status.has_started = true; adobe_connect_status.is_reg_open = false; adobe_connect_status.is_reg_closed = true; - general_status = 'live'; + general_status = "live"; stillReview = false; } } @@ -477,34 +1354,37 @@ if ( base.program.event.status = general_status; base.program.event.id = window?.programId || null; - console.log('timeUntilStart', timeUntilStart); + console.log("timeUntilStart", timeUntilStart); if (timeUntilStart.minutes <= 30) { if (!timeUntilInterval) { timeUntilInterval = setInterval(mczFrm_updateTimeUntil, 1000); } - } else if (timeUntilInterval) { - clearInterval(timeUntilInterval); - timeUntilInterval = null; + } else { + if (timeUntilInterval) { + clearInterval(timeUntilInterval); + timeUntilInterval = null; + } } } - function mczFrm_ACE_confirmURL(url_name = '', url = '') { + function mczFrm_ACE_confirmURL(url_name = "", url = "") { try { - const confirmLocation = window.mcz_marketoForm_pref?.program?.event?.adobe_connect?.urls?.[url_name] || null; + let confirmLocation = + window.mcz_marketoForm_pref?.program?.event?.adobe_connect?.urls?.[url_name] || null; if (confirmLocation == null) { return false; } - const current_status = confirmLocation?.valid_url || false; + let current_status = confirmLocation?.valid_url || false; if (current_status) { return true; } - if (url.trim() == '') { - // get the url from the config and we will validate it. - url = confirmLocation.url || ''; - if (url.trim() == '') { + if (url.trim() == "") { + //get the url from the config and we will validate it. + url = confirmLocation.url || ""; + if (url.trim() == "") { return false; } } @@ -517,7 +1397,7 @@ if ( } catch (e) { confirmLocation.valid_url = false; confirmLocation.url_obj = {}; - confirmLocation.url = ''; + confirmLocation.url = ""; return false; } return true; @@ -531,19 +1411,19 @@ if ( //* Communication frunctions //* async function mczFrm_createProgramSyncIframe() { - const mktToken = window.getMktToken; - const pageFromEventId = mcz_marketoForm_pref.program.event.id || ''; - if (pageFromEventId == '') { - console.log('No event id found, skipping profile sync iframe.'); + let mktToken = window.getMktToken; + let pageFromEventId = mcz_marketoForm_pref.program.event.id || ""; + if (pageFromEventId == "") { + console.log("No event id found, skipping profile sync iframe."); return; } - const munchkinId = MUNCHKIN_ID || '360-KCI-804'; + let munchkinId = MUNCHKIN_ID || "360-KCI-804"; addMunchkin(munchkinId, pageFromEventId, mktToken); - const programIDOnly = pageFromEventId.replace(/[^0-9]/g, ''); - const programfromStorage = await mczFrm_aquireFromStorage(`ev__${programIDOnly}`); + let programIDOnly = pageFromEventId.replace(/[^0-9]/g, ""); + let programfromStorage = await mczFrm_aquireFromStorage(`ev__${programIDOnly}`); if (programfromStorage) { - console.log('MCZ Form, Updating DL from storage:', programfromStorage); + console.log("MCZ Form, Updating DL from storage:", programfromStorage); mczFrm_updateDL(programfromStorage); } @@ -552,13 +1432,13 @@ if ( baseURL = `${baseURL}?mkt_tok=${mktToken}`; } - const iframe = document.createElement('iframe'); - iframe.sandbox = 'allow-scripts allow-same-origin'; + const iframe = document.createElement("iframe"); + iframe.sandbox = "allow-scripts allow-same-origin"; iframe.src = baseURL; - iframe.style.display = 'none'; - iframe.id = 'mcz-marketo-program-iframe'; + iframe.style.display = "none"; + iframe.id = "mcz-marketo-program-iframe"; document.body.appendChild(iframe); - console.log('Profile sync iframe added with URL:', iframe.src); + console.log("Profile sync iframe added with URL:", iframe.src); } function mczFrm_aquireFromStorage(lookupKey = null) { @@ -593,23 +1473,23 @@ if ( async function mczFrm_saveRefs(baseAlias = null, refStorageKey = null) { if (!refStorageKey) { - console.warn('No reference storage key found'); + console.warn("No reference storage key found"); return; } let existingRefs = []; - const newRefs = []; + let newRefs = []; try { - existingRefs = JSON.parse(localStorage.getItem(refStorageKey) || '[]'); + existingRefs = JSON.parse(localStorage.getItem(refStorageKey) || "[]"); } catch (e) { - console.warn('Error parsing refStorage', e); + console.warn("Error parsing refStorage", e); existingRefs = []; } const dataProfileKeys = existingRefs || []; const now = new Date().getTime(); - for (const key of dataProfileKeys) { + for (let key of dataProfileKeys) { const lookupKey = key; let itemStr = null; itemStr = sessionStorage.getItem(lookupKey); @@ -641,22 +1521,22 @@ if ( } if ( - baseAlias != null - && newRefs.indexOf(baseAlias) == -1 - && existingRefs.indexOf(baseAlias) == -1 + baseAlias != null && + newRefs.indexOf(baseAlias) == -1 && + existingRefs.indexOf(baseAlias) == -1 ) { newRefs.push(baseAlias); } localStorage.setItem(refStorageKey, JSON.stringify(newRefs)); - console.log('MCZ RefData: Updated refs in refStorage', newRefs); + console.log("MCZ RefData: Updated refs in refStorage", newRefs); } async function mczFrm_saveMsg(message) { try { const saveAlias = message?.alias || null; const refStorageKey = message?.refStorage || null; - const location = message?.location || 'local'; + const location = message?.location || "local"; const dataStr = JSON.stringify(message); const sizeInBytes = new Blob([dataStr]).size; const sizeInMB = sizeInBytes / (1024 * 1024); @@ -665,11 +1545,11 @@ if ( console.warn(`MCZ RefData: Large data size (${sizeInMB.toFixed(2)}MB)`); } if (!saveAlias) { - console.warn('No save alias found'); + console.warn("No save alias found"); return; } - if (location == 'session') { + if (location == "session") { sessionStorage.setItem(saveAlias, dataStr); } else { localStorage.setItem(saveAlias, dataStr); @@ -677,34 +1557,36 @@ if ( mczFrm_saveRefs(saveAlias, refStorageKey); } catch (storageError) { - console.warn('Storage error:', storageError); + console.warn("Storage error:", storageError); } } - window.addEventListener('message', (event) => { - const config = { allowedOrigins: ['https://engage.adobe.com', 'https://business.adobe.com'] }; - const eventOrigin = new URL(event.origin); + window.addEventListener("message", (event) => { + let config = { + allowedOrigins: ["https://engage.adobe.com", "https://business.adobe.com"], + }; + let eventOrigin = new URL(event.origin); let allowedToPass = false; for (let i = 0; i < config.allowedOrigins.length; i++) { - const allowedOriginURL = new URL(config.allowedOrigins[i]); + let allowedOriginURL = new URL(config.allowedOrigins[i]); if ( - eventOrigin.host === allowedOriginURL.host - && eventOrigin.protocol === allowedOriginURL.protocol - && eventOrigin.port === allowedOriginURL.port + eventOrigin.host === allowedOriginURL.host && + eventOrigin.protocol === allowedOriginURL.protocol && + eventOrigin.port === allowedOriginURL.port ) { allowedToPass = true; break; } } - if (event.data && event?.data?.type !== 'mcz_marketoForm_pref_sync') { + if (event.data && event?.data?.type !== "mcz_marketoForm_pref_sync") { allowedToPass = false; } if (!allowedToPass) { return; } - console.log('MCZ RefData Received:', event.data); + console.log("MCZ RefData Received:", event.data); if (event.data && event?.data?.target_path !== null && event?.data?.target_attribute !== null) { - const save = event?.data?.save || false; + let save = event?.data?.save || false; mczFrm_updateDL(event?.data); if (save) { mczFrm_saveMsg(event?.data); @@ -716,81 +1598,118 @@ if ( if (data == null) { return; } - const targetPath = data?.target_path || null; + let targetPath = data?.target_path || null; if (targetPath == null) { return; } - let program_type = data?.data?.program?.type || 'default'; - let program_status = 'default'; + let program_type = data?.data?.program?.type || "default"; + let program_status = "default"; - const this_data = JSON.parse(JSON.stringify(data?.data)); - if (targetPath == 'root.program_profile') { + let this_data = JSON.parse(JSON.stringify(data?.data)); + if (targetPath == "root.program_profile") { window.mcz_marketoForm_pref.program_profile = this_data; - } else if (targetPath == 'root.profile') { + } else if (targetPath == "root.profile") { window.mcz_marketoForm_pref.profile = this_data; - } else if (targetPath == 'root.form') { + } else if (targetPath == "root.form") { window.mcz_marketoForm_pref.form = this_data; - } else if (targetPath == 'root.profile.acc') { + } else if (targetPath == "root.profile.acc") { window.mcz_marketoForm_pref.profile.acc = this_data; - } else if (targetPath == 'root.program') { + } else if (targetPath == "root.program") { window.mcz_marketoForm_pref.program = this_data; - program_type = this_data?.type || 'default'; - } else if (targetPath == 'root.program.event') { + program_type = this_data?.type || "default"; + } else if (targetPath == "root.program.event") { window.mcz_marketoForm_pref.program.event = this_data; - program_type = this_data?.type || 'default'; + program_type = this_data?.type || "default"; } - if (window.mcz_marketoForm_pref?.program?.type == 'event') { + if (window.mcz_marketoForm_pref?.program?.type == "event") { mczFrm_updateTimeUntil(); - if (window.mcz_marketoForm_pref?.program?.event?.type == 'adobe_connect') { - program_type = 'adobe_connect'; - program_status = window.mcz_marketoForm_pref?.program?.event?.adobe_connect?.status?.overall || 'default'; + if (window.mcz_marketoForm_pref?.program?.event?.type == "adobe_connect") { + program_type = "adobe_connect"; + program_status = + window.mcz_marketoForm_pref?.program?.event?.adobe_connect?.status?.overall || "default"; } } - function mczFrm_statusLbls(program_type = '', program_status = '') { - if (program_type == '' || program_status == '') { - console.log('No program type or status found'); + function mczFrm_statusLbls(program_type = "", program_status = "") { + if (program_type == "" || program_status == "") { + console.log("No program type or status found"); return; } - const dataLabel = 'data-mcz-dl-status'; - const elements = document.querySelectorAll(`[${dataLabel}]`); - const timeNow = new Date().getTime(); + let dataLabel = "data-mcz-dl-status"; + let elements = document.querySelectorAll(`[${dataLabel}]`); + let timeNow = new Date().getTime(); for (let i = 0; i < elements.length; i++) { - const element = elements[i]; + let element = elements[i]; element.setAttribute(`${dataLabel}-dt`, timeNow); element.setAttribute(`${dataLabel}-type`, program_type); element.setAttribute(`${dataLabel}`, program_status); } } - console.log('Status Labels:', program_type, program_status); + console.log("Status Labels:", program_type, program_status); mczFrm_statusLbls(program_type, program_status); } - function mczFrm_sendMessage(msgName = null, targetPath = 'root.program', data = {}) { - const iframe = document.getElementById('mcz-marketo-program-iframe'); + function mczFrm_sendMessage(msgName = null, targetPath = "root.program", data = {}) { + let iframe = document.getElementById("mcz-marketo-program-iframe"); if (iframe) { - const message = { - type: 'mcz_marketoForm_pref_sync', + let message = { + type: "mcz_marketoForm_pref_sync", data: { target_path: targetPath, - data, + data: data, }, }; - iframe.contentWindow.postMessage(message, 'https://engage.adobe.com'); + iframe.contentWindow.postMessage(message, "https://engage.adobe.com"); } else { - console.warn('No iframe found'); + console.warn("No iframe found"); } } + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* + //* let maxTries = 1000; - const checkResourceLocation = async () => { + let checkResourceLocation = async () => { if (maxTries <= 0) { - console.log('maxTries reached', maxTries); + console.log("maxTries reached", maxTries); return; } maxTries--; From 292851a966a90e4e0abc7b5cdbac1e07748aa2ee Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Wed, 23 Jul 2025 19:07:33 +0530 Subject: [PATCH 63/93] adding status listener to chronobox for now --- events/blocks/chrono-box/chrono-box.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/events/blocks/chrono-box/chrono-box.js b/events/blocks/chrono-box/chrono-box.js index 1e655ffd..095eeac4 100644 --- a/events/blocks/chrono-box/chrono-box.js +++ b/events/blocks/chrono-box/chrono-box.js @@ -109,6 +109,8 @@ export default async function init(el) { import(`${LIBS}/features/spectrum-web-components/dist/progress-circle.js`), ]); + el.setAttribute('data-mcz-dl-status', 'loading'); + const blockConfig = readBlockConfig(el); const scheduleId = blockConfig?.['schedule-id']; let staticSchedule; From 91a0e6aca7551f5db6a135638b0271401af177d9 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Thu, 24 Jul 2025 00:21:45 +0530 Subject: [PATCH 64/93] chrono box enhancement --- events/blocks/chrono-box/chrono-box.js | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/events/blocks/chrono-box/chrono-box.js b/events/blocks/chrono-box/chrono-box.js index 095eeac4..4510cedc 100644 --- a/events/blocks/chrono-box/chrono-box.js +++ b/events/blocks/chrono-box/chrono-box.js @@ -1,4 +1,4 @@ -// import { metadataStore } from '../../features/timing-framework/plugins/metadata/plugin.js'; +import { metadataStore } from '../../features/timing-framework/plugins/metadata/plugin.js'; import { readBlockConfig, LIBS, getMetadata, setMetadata } from '../../scripts/utils.js'; function buildScheduleDoubleLinkedList(entries) { @@ -172,30 +172,13 @@ export default async function init(el) { el.classList.add('error'); }); }; - setMetadata('adobe-connect-url', 'https://newadmin.dev.adobeconnect.com/gbajaj?guestname=Participant&proto=true'); - - - // setTimeout(() => { - // console.log('setting video'); - // metadataStore.set('marketo-next', 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'); - // }, 10000); function mczMarketoFormAdobeConnectEvent() { if (window.mcz_marketoForm_pref?.form?.success?.type === 'adobe_connect') { const eventUrl = window.mcz_marketoForm_pref?.form?.success?.content; setMetadata('adobe-connect-url', eventUrl); - // window.join_url = eventUrl; + metadataStore.set('marketo-next', ''); } - - // if (document.querySelector(".marketo-form-wrapper")) { - // document.querySelector(".marketo-form-wrapper").classList.add("hide"); - // } - // // console.log("adobe_connect_event in Events", eventUrl); - - // const joinButton = document.querySelector('.adobe-connect button[daa-ll*="Join"]'); - // if (joinButton) { - // document.querySelector('.adobe-connect button[daa-ll*="Join"]').click(); - // } } // Debounce function to limit rapid calls From 9df743cc72f963dbdcb08081cc7ee5c979071a15 Mon Sep 17 00:00:00 2001 From: ambalika91 Date: Thu, 24 Jul 2025 11:11:37 +0530 Subject: [PATCH 65/93] fix css property --- events/blocks/adobe-connect/adobe-connect.css | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/events/blocks/adobe-connect/adobe-connect.css b/events/blocks/adobe-connect/adobe-connect.css index d0c84a48..cfd68091 100644 --- a/events/blocks/adobe-connect/adobe-connect.css +++ b/events/blocks/adobe-connect/adobe-connect.css @@ -36,8 +36,8 @@ /* Overlay background */ .iframe-overlay { position: fixed; - top: 0; left: 0; width: 100%; height: 100%; - background: rgba(0, 0, 0, 0.85); + inset: 0; + background: rgba(0, 0, 0, 85%); color: #fff; display: flex; flex-direction: column; @@ -64,17 +64,7 @@ } /* Heading */ -.iframe-overlay .overlay-heading { - font-weight: 700; - text-align: center; - line-height: 125%; - font-style: normal; - color: #fff; - font-size: 24px; - align-self: stretch; - margin: 0; -} - +.iframe-overlay .overlay-heading, .iframe-overlay .overlay-heading-yrs { font-weight: 700; text-align: center; From 9e1c9adbfdb833aaeed20e88a93c79dddba9e36f Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Thu, 24 Jul 2025 14:16:59 +0530 Subject: [PATCH 66/93] fixing duplicates --- rs/360-KCI-804/images/mktoTestFormConfig.js | 865 +------------------- 1 file changed, 1 insertion(+), 864 deletions(-) diff --git a/rs/360-KCI-804/images/mktoTestFormConfig.js b/rs/360-KCI-804/images/mktoTestFormConfig.js index 32da191c..1e96f96f 100644 --- a/rs/360-KCI-804/images/mktoTestFormConfig.js +++ b/rs/360-KCI-804/images/mktoTestFormConfig.js @@ -18,870 +18,7 @@ if ( const urlParams = new URLSearchParams(window.location.search); if (urlParams.has(storageKey)) { - mktToken = urlParams.get(storageKey);// ## - // ## Test Module - Just a rough test module to set the config of the form.11 - // ## - - if ( - typeof mczFrm_mkto_testing_loader != "function" && - typeof mczFrm_mkto_testing_loader == "undefined" - ) { - //* - //* - async function getMktToken() { - const storageKey = "mkt_tok"; - let mktToken = ""; - - if (window.__mktTokVal && window.__mktTokVal?.trim()?.length > 0) { - return window.__mktTokVal; - } - - const urlParams = new URLSearchParams(window.location.search); - if (urlParams.has(storageKey)) { - mktToken = urlParams.get(storageKey); - try { - sessionStorage.setItem(storageKey, mktToken); - localStorage.setItem(storageKey, mktToken); - } catch (e) { - console.warn(`Could not save ${storageKey} to storage`, e); - } - } else { - mktToken = sessionStorage.getItem(storageKey) || localStorage.getItem(storageKey) || ""; - } - - window.__mktTokVal = mktToken; - return mktToken; - } - - window.getMktToken = await getMktToken(); - - //* - //* - //* - //* - //* - //* - //* - //* - //* - - //hide Join button - - var BASE_URL = "https://engage.marketo.com"; - var MUNCHKIN_ID = "360-KCI-804"; - var resourceLocation = ".chrono-box"; - var resourceWatch = '.chrono-box'; - let mczFrm_mkto_testing_loader = () => { - let cssFast = ` - button[daa-ll="Join the event-1--"] { - visibility: hidden !important; - opacity: 0 !important; - } - `; - let cssLinkFast = document.createElement("style"); - cssLinkFast.innerHTML = cssFast; - document.head.appendChild(cssLinkFast); - - let formID = 3131; - let resourceFormHTML = ` -
-
- - - -
-
- `; - - const marketoCSSresource = "https://business.adobe.com/libs/blocks/marketo/marketo.css"; - - let marketoConfiguratorLink = - "eyJmb3JtLnRlbXBsYXRlIjoicmVxdWVzdF9mb3JfaW5mb3JtYXRpb24iLCJmb3JtLnN1YnR5cGUiOiJyZXF1ZXN0X2Zvcl9pbmZvcm1hdGlvbiIsInByb2dyYW0uY2FtcGFpZ25pZHMuc2ZkYyI6IjcwMTE0MDAwMDAyWFl2SUFBVyIsInByb2dyYW0ucG9pIjoiTUFSS0VUT0VOR0FHRU1FTlRQTEFURk9STSIsImZvcm0uc3VjY2Vzcy5jb250ZW50IjoiaHR0cHM6Ly9idXNpbmVzcy5hZG9iZS5jb20vcmVzb3VyY2VzL2Vib29rcy9wcm92aW5nLXRoZS1pbXBhY3Qtb2YtbWFya2V0aW5nLW9uLXJldmVudWUvdGhhbmsteW91Lmh0bWwiLCJmb3JtLnN1Y2Nlc3MudHlwZSI6IiIsInByb2dyYW0uY29udGVudC50eXBlIjoiIiwicHJvZ3JhbS5jb250ZW50LmlkIjoiIiwiZmllbGRfdmlzaWJpbGl0eS5uYW1lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBob25lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnkiOiJyZXF1aXJlZCIsImZpZWxkX3Zpc2liaWxpdHkud2Vic2l0ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5mdW5jdGlvbmFsX2FyZWEiOiJGdW5jdGlvbmFsIEFyZWEtRFgiLCJmaWVsZF92aXNpYmlsaXR5LnN0YXRlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBvc3Rjb2RlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnlfc2l6ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5wcm9kdWN0cyI6ImhpZGRlbiIsImZpZWxkX2ZpbHRlcnMuaW5kdXN0cnkiOiJoaWRkZW4iLCJmaWVsZF9maWx0ZXJzLmpvYl9yb2xlIjoiYWxsIiwiZmllbGRfdmlzaWJpbGl0eS5jb21tZW50cyI6ImhpZGRlbiIsImZpZWxkX3Zpc2liaWxpdHkuZGVtbyI6ImhpZGRlbiIsInByb2dyYW0uY29wYXJ0bmVybmFtZXMiOiIiLCJwcm9ncmFtLmNhbXBhaWduaWRzLmV4dGVybmFsIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5yZXRvdWNoIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5vbnNpdGUiOiIiLCJwcm9ncmFtLmFkZGl0aW9uYWxfZm9ybV9pZCI6IiIsImZvcm0gaWQiOiIxNzIzIiwibWFya2V0byBtdW5ja2luIjoiMzYwLUtDSS04MDQiLCJtYXJrZXRvIGhvc3QiOiJlbmdhZ2UuYWRvYmUuY29tIiwiZm9ybSB0eXBlIjoibWFya2V0b19mb3JtIn0"; - let marketoConfiguratorHTML = ` -
- -
-
Marketo Configurator
-
-
- `; - - const cssLink = document.createElement("link"); - cssLink.rel = "stylesheet"; - cssLink.href = marketoCSSresource; - document.head.appendChild(cssLink); - - let marketoConfiguratorJSON = {}; - try { - marketoConfiguratorJSON = JSON.parse( - decodeURIComponent(escape(window.atob(marketoConfiguratorLink))) - ); - } catch (e) { - console.error("Error parsing Marketo Configurator JSON", e); - } - - let use_marketoConfiguratorLink = false; - - let mcz_marketoForm_pref_local = { - sync_profiles: {}, - "marketo munckin": "360-KCI-804", - "marketo host": "engage.adobe.com", - "form id": "3131", - form: { - template: "flex_event", - success: { - type: "adobe_connect", - content: "https://livekitqe.dev.adobeconnect.com/paxlkm0gwsj4", - delay: 5000, - confirm: false, - }, - baseSite: "https://business.adobe.com", - id: 3131, - }, - program: { - campaignids: { - sfdc: "7015Y000004BWOnQAO", - external: "", - retouch: "", - onsite: "", - cgen: "", - cuid: "", - }, - poi: "MARKETOENGAGEMENTPLATFORM", - additional_form_id: "", - copartnernames: "", - marketo_asset: { - name: "", - id: "", - }, - event: { - type: "adobe_connect", //connect_recording or video - subtype: "flex_event", - id: "mcz114328", - status: { - viewport: { - width: 1024, - height: 768, - active: true, - audio: true, - }, - activity: { - start: "2025-06-07-10:00", - end: "2025-06-07-10:00", - duration_ticks: 1000, - active_ticks: 1000, - log: [ - { - type: "adobe_connect", - subtype: "flex_event", - id: "ACTEST4242", - }, - ], - }, - activities: [], - }, - }, - status: { - label: "invited", - milestone: "responded", - is: "1001", - dateTime: "2025-06-07-10:00", - }, - status_previous: { - label: "invited", - milestone: "responded", - is: "1001", - dateTime: "2025-06-07-10:00", - }, - }, - field_visibility: { - name: "required", - phone: "hidden", - company: "visible", - website: "hidden", - state: "hidden", - postcode: "hidden", - }, - field_filters: { - functional_area: "Functional Area-DX", - products: "hidden", - industry: "hidden", - job_role: "hidden", - comments: "hidden", - demo: "hidden", - }, - }; - - if (use_marketoConfiguratorLink) { - for (let key in marketoConfiguratorJSON) { - let keyArray = key.split("."); - let obj = mcz_marketoForm_pref_local; - for (let i = 0; i < keyArray.length - 1; i++) { - if (!obj[keyArray[i]]) { - obj[keyArray[i]] = {}; - } - obj = obj[keyArray[i]]; - } - obj[keyArray[keyArray.length - 1]] = marketoConfiguratorJSON[key]; - } - } - - if (!window.location.search.includes("preview=1")) { - history.pushState({}, "", `${window.location.pathname}?preview=1`); - } - - window.mcz_marketoForm_pref = JSON.parse(JSON.stringify(mcz_marketoForm_pref_local)); - - var loadScript = (url, type, { mode } = {}) => - new Promise((resolve, reject) => { - let script = document.querySelector(`head > script[src="${url}"]`); - if (!script) { - const { head } = document; - script = document.createElement("script"); - script.setAttribute("src", url); - if (type) { - script.setAttribute("type", type); - } - if (["async", "defer"].includes(mode)) script.setAttribute(mode, true); - head.append(script); - } - - if (script.dataset.loaded) { - resolve(script); - return; - } - - const onScript = (event) => { - script.removeEventListener("load", onScript); - script.removeEventListener("error", onScript); - - if (event.type === "error") { - reject(new Error(`error loading script: ${script.src}`)); - } else if (event.type === "load") { - script.dataset.loaded = true; - resolve(script); - } - }; - - script.addEventListener("load", onScript); - script.addEventListener("error", onScript); - }); - - const resourceForm = document.createElement("div"); - resourceForm.innerHTML = resourceFormHTML; - if (document.querySelector(resourceLocation)) { - document.querySelector(resourceLocation).appendChild(resourceForm); - } else { - console.log("resourceLocation not found", resourceLocation); - } - - loadScript(`${BASE_URL}/js/forms2/js/forms2.min.js`) - .then(() => { - const { MktoForms2 } = window; - if (!MktoForms2) throw new Error("Marketo forms not loaded"); - - MktoForms2.loadForm(`${BASE_URL}`, MUNCHKIN_ID, formID); - MktoForms2.whenReady((form) => { - console.log("Marketo Form Thinks it's Ready", form); - }); - }) - .catch(() => { - console.error("Error loading Marketo form"); - }); - - window.addMunchkin = async function ( - munchkinId = "360-KCI-804", - pageFromEventId = "", - mktToken = "" - ) { - loadScript(`https://munchkin.marketo.net/munchkin.js`) - .then(() => { - Munchkin.init(munchkinId, { - customName: `Testing BACOM Connect UX ${pageFromEventId}`, - mkt_tok: mktToken, - }); - }) - .catch(() => { - console.error("Error loading Munchkin.js"); - }); - }; - - mczFrm_createProgramSyncIframe(); - }; - - window.mcz_marketoForm_adobe_connect_event = (event_url = "") => { - let final_url = ""; - if (event_url != "") { - final_url = event_url.trim(); - } - - if (document.querySelector(".marketo-form-wrapper")) { - document.querySelector(".marketo-form-wrapper").classList.add("hide"); - } - if (document.querySelector('.adobe-connect button[daa-ll*="Join"]')) { - document.querySelector('.adobe-connect button[daa-ll*="Join"]').click(); - } - console.log("adobe_connect_event", final_url); - mczFrm_sendMessage("reg_submitted", "root.program_profile"); - }; - - // - // - // - // - // - // - - function mczFrm_getTimeUntil(targetDate, nowDate) { - const timeUntil = targetDate - nowDate; - - if (timeUntil <= 0) { - return { days: 0, hours: 0, minutes: 0, seconds: 0, timeUntil }; - } - - const days = Math.floor(timeUntil / (1000 * 60 * 60 * 24)); - const hours = Math.floor((timeUntil % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); - const minutes = Math.floor((timeUntil % (1000 * 60 * 60)) / (1000 * 60)); - const seconds = Math.floor((timeUntil % (1000 * 60)) / 1000); - - return { days, hours, minutes, seconds, timeUntil }; - } - - function mczFrm_currentMarketoTime() { - let serverTimeOffset; - let serverTimeRaw = mcz_marketoForm_pref?.program?.marketo_asset?.time?.systemDateTime || null; - try { - if (serverTimeRaw) { - let serverTimeInitial = new Date(serverTimeRaw).getTime(); - if (!isNaN(serverTimeInitial)) { - let clientTimeInitial = new Date().getTime(); - serverTimeOffset = serverTimeInitial - clientTimeInitial; - } - } else { - serverTimeOffset = 0; - } - } catch (e) { - console.warn("Error getting server time offset", e); - serverTimeOffset = 0; - } - if (typeof serverTimeOffset === "undefined") { - return new Date(); - } - return new Date(new Date().getTime() + serverTimeOffset); - } - - var timeUntilInterval = null; - function mczFrm_updateTimeUntil() { - let base = window?.mcz_marketoForm_pref || {}; - let endDateTime = base?.program?.event?.dateTime?.pst?.dateTimeEnd || null; - let startDateTime = base?.program?.event?.dateTime?.pst?.dateTimeStart || null; - let nowDateTime = mczFrm_currentMarketoTime(); - let general_status = "pending"; - if (endDateTime == null || startDateTime == null || nowDateTime == null) { - console.warn("No end or now date time found for this event"); - return null; - } - - let adobe_connect_status = base?.program?.event?.adobe_connect?.status || null; - - if (adobe_connect_status == null) { - adobe_connect_status = {}; - } - - let endDate = new Date(endDateTime); - let startDate = new Date(startDateTime); - let nowDate = new Date(nowDateTime); - let timeUntilEnds = mczFrm_getTimeUntil(endDate, nowDate); - let timeUntilStart = mczFrm_getTimeUntil(startDate, nowDate); - - let stillReview = true; - - // Reset status flags - adobe_connect_status.is_starting_soon = false; - adobe_connect_status.is_starting_in_5_minutes = false; - adobe_connect_status.is_starting_in_1_minute = false; - adobe_connect_status.is_halfway_through = false; - adobe_connect_status.about_to_end = false; - adobe_connect_status.has_ended = false; - adobe_connect_status.has_finished = false; - adobe_connect_status.can_enter = false; - adobe_connect_status.can_attend = false; - adobe_connect_status.can_register = false; - adobe_connect_status.has_started = false; - adobe_connect_status.is_reg_open = false; - adobe_connect_status.is_reg_closed = false; - general_status = "register"; - - if (timeUntilInterval) { - clearInterval(timeUntilInterval); - } - - // Set timing status flags based on time until start - if (timeUntilStart.timeUntil > 0 && stillReview) { - if (timeUntilStart.minutes <= 10) { - adobe_connect_status.is_starting_soon = true; - } - if (timeUntilStart.minutes <= 5) { - adobe_connect_status.is_starting_in_5_minutes = true; - } - if (timeUntilStart.minutes <= 1) { - adobe_connect_status.is_starting_in_1_minute = true; - } - } - - let duration = mczFrm_getTimeUntil(endDate, startDate); - base.program.event.dateTime.duration = duration; - - let remaining = mczFrm_getTimeUntil(endDate, nowDate); - base.program.event.dateTime.remaining = remaining; - - // Calculate halfway point using total milliseconds for accuracy - if (duration?.timeUntil > 0 && stillReview) { - let half_duration_ms = duration.timeUntil / 2; - if (remaining?.timeUntil <= half_duration_ms && remaining?.timeUntil > 0) { - adobe_connect_status.is_halfway_through = true; - } - } - - // Check if event is about to end - if (remaining?.timeUntil > 0 && remaining.minutes <= 10 && stillReview) { - adobe_connect_status.about_to_end = true; - } - - //check if finished - if ( - adobe_connect_status.has_started && - remaining?.timeUntil > 0 && - remaining.minutes <= 2 && - stillReview - ) { - adobe_connect_status.has_ended = true; - adobe_connect_status.has_finished = true; - adobe_connect_status.is_reg_open = false; - adobe_connect_status.is_reg_closed = true; - adobe_connect_status.can_enter = false; - adobe_connect_status.can_attend = false; - adobe_connect_status.can_register = false; - adobe_connect_status.has_started = true; - general_status = "finished"; - stillReview = false; - } - - //open_minutes and close_minutes - let open_minutes = base?.program?.event?.dateTime?.pst?.open_minutes || 10; //you can join 10 minutes before the event starts - let close_minutes = base?.program?.event?.dateTime?.pst?.close_minutes || 999; //you can join 999 minutes after the event starts - - //workout if the event is open or closed - let doorsOpen = false; - if (timeUntilStart?.minutes > 0 && stillReview) { - if (timeUntilStart?.minutes <= open_minutes) { - doorsOpen = true; - adobe_connect_status.can_enter = true; - adobe_connect_status.can_attend = true; - adobe_connect_status.can_register = true; - adobe_connect_status.has_started = true; - adobe_connect_status.has_ended = false; - adobe_connect_status.is_reg_open = true; - adobe_connect_status.is_reg_closed = false; - general_status = "live"; - stillReview = false; - } - } - if (doorsOpen) { - if (duration?.minutes >= close_minutes && stillReview) { - doorsOpen = false; - adobe_connect_status.can_enter = false; - adobe_connect_status.can_attend = false; - adobe_connect_status.can_register = false; - adobe_connect_status.has_started = true; - adobe_connect_status.is_reg_open = false; - adobe_connect_status.is_reg_closed = true; - general_status = "live"; - stillReview = false; - } - } - - base.program.event.dateTime.timeUntil = { - starts: timeUntilStart, - ends: timeUntilEnds, - }; - adobe_connect_status.overall = general_status; - base.program.event.status = general_status; - base.program.event.id = window?.programId || null; - - console.log("timeUntilStart", timeUntilStart); - - if (timeUntilStart.minutes <= 30) { - if (!timeUntilInterval) { - timeUntilInterval = setInterval(mczFrm_updateTimeUntil, 1000); - } - } else { - if (timeUntilInterval) { - clearInterval(timeUntilInterval); - timeUntilInterval = null; - } - } - } - - function mczFrm_ACE_confirmURL(url_name = "", url = "") { - try { - let confirmLocation = - window.mcz_marketoForm_pref?.program?.event?.adobe_connect?.urls?.[url_name] || null; - if (confirmLocation == null) { - return false; - } - - let current_status = confirmLocation?.valid_url || false; - if (current_status) { - return true; - } - - if (url.trim() == "") { - //get the url from the config and we will validate it. - url = confirmLocation.url || ""; - if (url.trim() == "") { - return false; - } - } - - confirmLocation.url = url; - - try { - confirmLocation.url_obj = new URL(url); - confirmLocation.valid_url = true; - } catch (e) { - confirmLocation.valid_url = false; - confirmLocation.url_obj = {}; - confirmLocation.url = ""; - return false; - } - return true; - } catch (e) { - return false; - } - } - //* - //* - //* - //* Communication frunctions - //* - async function mczFrm_createProgramSyncIframe() { - let mktToken = window.getMktToken; - let pageFromEventId = mcz_marketoForm_pref.program.event.id || ""; - if (pageFromEventId == "") { - console.log("No event id found, skipping profile sync iframe."); - return; - } - - let munchkinId = MUNCHKIN_ID || "360-KCI-804"; - addMunchkin(munchkinId, pageFromEventId, mktToken); - let programIDOnly = pageFromEventId.replace(/[^0-9]/g, ""); - let programfromStorage = await mczFrm_aquireFromStorage(`ev__${programIDOnly}`); - if (programfromStorage) { - console.log("MCZ Form, Updating DL from storage:", programfromStorage); - mczFrm_updateDL(programfromStorage); - } - - let baseURL = `https://engage.adobe.com/${pageFromEventId}.html`; - if (mktToken) { - baseURL = `${baseURL}?mkt_tok=${mktToken}`; - } - - const iframe = document.createElement("iframe"); - iframe.sandbox = "allow-scripts allow-same-origin"; - iframe.src = baseURL; - iframe.style.display = "none"; - iframe.id = "mcz-marketo-program-iframe"; - document.body.appendChild(iframe); - console.log("Profile sync iframe added with URL:", iframe.src); - } - - function mczFrm_aquireFromStorage(lookupKey = null) { - const now = new Date().getTime(); - - let itemStr = null; - itemStr = sessionStorage.getItem(lookupKey); - if (!itemStr) { - itemStr = localStorage.getItem(lookupKey); - } - if (!itemStr) { - return null; - } - - try { - const item = JSON.parse(itemStr); - const shelfLife = item?.shelf_life || 0; - const timestamp = item?.timestamp || 0; - const expires = item?.expires || 0; - - if (now - timestamp > shelfLife || now > expires) { - sessionStorage.removeItem(lookupKey); - localStorage.removeItem(lookupKey); - console.log(`MCZ RefData: Expired program removed from ${lookupKey}`); - return null; - } - return item; - } catch (e) { - return null; - } - } - - async function mczFrm_saveRefs(baseAlias = null, refStorageKey = null) { - if (!refStorageKey) { - console.warn("No reference storage key found"); - return; - } - - let existingRefs = []; - let newRefs = []; - try { - existingRefs = JSON.parse(localStorage.getItem(refStorageKey) || "[]"); - } catch (e) { - console.warn("Error parsing refStorage", e); - existingRefs = []; - } - - const dataProfileKeys = existingRefs || []; - const now = new Date().getTime(); - - for (let key of dataProfileKeys) { - const lookupKey = key; - let itemStr = null; - itemStr = sessionStorage.getItem(lookupKey); - if (!itemStr) { - itemStr = localStorage.getItem(lookupKey); - } - if (!itemStr) { - continue; - } - - try { - const item = JSON.parse(itemStr); - const shelfLife = item?.shelf_life || 0; - const timestamp = item?.timestamp || 0; - const expires = item?.expires || 0; - - if (now - timestamp > shelfLife || now > expires) { - sessionStorage.removeItem(lookupKey); - localStorage.removeItem(lookupKey); - console.log(`MCZ RefData: Expired ref removed from ${lookupKey}`); - } else { - newRefs.push(lookupKey); - } - } catch (e) { - console.warn(`Error parsing dataProfile for key: ${lookupKey}`, e); - sessionStorage.removeItem(lookupKey); - localStorage.removeItem(lookupKey); - } - } - - if ( - baseAlias != null && - newRefs.indexOf(baseAlias) == -1 && - existingRefs.indexOf(baseAlias) == -1 - ) { - newRefs.push(baseAlias); - } - - localStorage.setItem(refStorageKey, JSON.stringify(newRefs)); - console.log("MCZ RefData: Updated refs in refStorage", newRefs); - } - - async function mczFrm_saveMsg(message) { - try { - const saveAlias = message?.alias || null; - const refStorageKey = message?.refStorage || null; - const location = message?.location || "local"; - const dataStr = JSON.stringify(message); - const sizeInBytes = new Blob([dataStr]).size; - const sizeInMB = sizeInBytes / (1024 * 1024); - - if (sizeInMB > 2) { - console.warn(`MCZ RefData: Large data size (${sizeInMB.toFixed(2)}MB)`); - } - if (!saveAlias) { - console.warn("No save alias found"); - return; - } - - if (location == "session") { - sessionStorage.setItem(saveAlias, dataStr); - } else { - localStorage.setItem(saveAlias, dataStr); - } - - mczFrm_saveRefs(saveAlias, refStorageKey); - } catch (storageError) { - console.warn("Storage error:", storageError); - } - } - - window.addEventListener("message", (event) => { - let config = { - allowedOrigins: ["https://engage.adobe.com", "https://business.adobe.com"], - }; - let eventOrigin = new URL(event.origin); - let allowedToPass = false; - for (let i = 0; i < config.allowedOrigins.length; i++) { - let allowedOriginURL = new URL(config.allowedOrigins[i]); - if ( - eventOrigin.host === allowedOriginURL.host && - eventOrigin.protocol === allowedOriginURL.protocol && - eventOrigin.port === allowedOriginURL.port - ) { - allowedToPass = true; - break; - } - } - if (event.data && event?.data?.type !== "mcz_marketoForm_pref_sync") { - allowedToPass = false; - } - if (!allowedToPass) { - return; - } - console.log("MCZ RefData Received:", event.data); - if (event.data && event?.data?.target_path !== null && event?.data?.target_attribute !== null) { - let save = event?.data?.save || false; - mczFrm_updateDL(event?.data); - if (save) { - mczFrm_saveMsg(event?.data); - } - } - }); - - function mczFrm_updateDL(data = null) { - if (data == null) { - return; - } - let targetPath = data?.target_path || null; - if (targetPath == null) { - return; - } - let program_type = data?.data?.program?.type || "default"; - let program_status = "default"; - - let this_data = JSON.parse(JSON.stringify(data?.data)); - if (targetPath == "root.program_profile") { - window.mcz_marketoForm_pref.program_profile = this_data; - } else if (targetPath == "root.profile") { - window.mcz_marketoForm_pref.profile = this_data; - } else if (targetPath == "root.form") { - window.mcz_marketoForm_pref.form = this_data; - } else if (targetPath == "root.profile.acc") { - window.mcz_marketoForm_pref.profile.acc = this_data; - } else if (targetPath == "root.program") { - window.mcz_marketoForm_pref.program = this_data; - program_type = this_data?.type || "default"; - } else if (targetPath == "root.program.event") { - window.mcz_marketoForm_pref.program.event = this_data; - program_type = this_data?.type || "default"; - } - - if (window.mcz_marketoForm_pref?.program?.type == "event") { - mczFrm_updateTimeUntil(); - if (window.mcz_marketoForm_pref?.program?.event?.type == "adobe_connect") { - program_type = "adobe_connect"; - program_status = - window.mcz_marketoForm_pref?.program?.event?.adobe_connect?.status?.overall || "default"; - } - } - - function mczFrm_statusLbls(program_type = "", program_status = "") { - if (program_type == "" || program_status == "") { - console.log("No program type or status found"); - return; - } - - let dataLabel = "data-mcz-dl-status"; - let elements = document.querySelectorAll(`[${dataLabel}]`); - let timeNow = new Date().getTime(); - for (let i = 0; i < elements.length; i++) { - let element = elements[i]; - element.setAttribute(`${dataLabel}-dt`, timeNow); - element.setAttribute(`${dataLabel}-type`, program_type); - element.setAttribute(`${dataLabel}`, program_status); - } - } - - console.log("Status Labels:", program_type, program_status); - - mczFrm_statusLbls(program_type, program_status); - } - - function mczFrm_sendMessage(msgName = null, targetPath = "root.program", data = {}) { - let iframe = document.getElementById("mcz-marketo-program-iframe"); - if (iframe) { - let message = { - type: "mcz_marketoForm_pref_sync", - data: { - target_path: targetPath, - data: data, - }, - }; - - iframe.contentWindow.postMessage(message, "https://engage.adobe.com"); - } else { - console.warn("No iframe found"); - } - } - - //* - //* - //* - //* - //* - //* - //* - //* - //* - //* - //* - //* - //* - //* - //* - //* - //* - //* - //* - //* - //* - //* - //* - //* - //* - //* - //* - //* - //* - //* - //* - //* - //* - //* - //* - //* - let maxTries = 1000; - let checkResourceLocation = async () => { - if (maxTries <= 0) { - console.log("maxTries reached", maxTries); - return; - } - maxTries--; - if (document.querySelector(resourceWatch)) { - mczFrm_mkto_testing_loader(); - } else { - await new Promise((resolve) => setTimeout(resolve, 25)); - checkResourceLocation(); - } - }; - checkResourceLocation(); - } - - // ## - // ## + mktToken = urlParams.get(storageKey); try { sessionStorage.setItem(storageKey, mktToken); localStorage.setItem(storageKey, mktToken); From bec117a0f538a64a76d76598d5ec3c67397e3563 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Thu, 24 Jul 2025 14:40:31 +0530 Subject: [PATCH 67/93] set status active on registration --- rs/360-KCI-804/images/mktoTestFormConfig.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rs/360-KCI-804/images/mktoTestFormConfig.js b/rs/360-KCI-804/images/mktoTestFormConfig.js index 1e96f96f..e27a186a 100644 --- a/rs/360-KCI-804/images/mktoTestFormConfig.js +++ b/rs/360-KCI-804/images/mktoTestFormConfig.js @@ -305,6 +305,11 @@ if ( } console.log("adobe_connect_event", final_url); mczFrm_sendMessage("reg_submitted", "root.program_profile"); + + const resource = document.querySelector(resourceWatch); + if(resource) { + resource.setAttribute('data-mcz-dl-status', 'active'); + } }; // From 2dac64fac7e39a8743daa061808d1d63ea7f1830 Mon Sep 17 00:00:00 2001 From: ambalika91 Date: Thu, 24 Jul 2025 17:49:14 +0530 Subject: [PATCH 68/93] change name of asset --- events/blocks/adobe-connect/adobe-connect.js | 2 +- events/blocks/adobe-connect/asset/{Frame.svg => Cross.svg} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename events/blocks/adobe-connect/asset/{Frame.svg => Cross.svg} (100%) diff --git a/events/blocks/adobe-connect/adobe-connect.js b/events/blocks/adobe-connect/adobe-connect.js index 3f94c634..83885135 100644 --- a/events/blocks/adobe-connect/adobe-connect.js +++ b/events/blocks/adobe-connect/adobe-connect.js @@ -63,7 +63,7 @@ function createOverlay(rowBlock) { { class: 'overlay-close-btn', 'aria-label': 'Close overlay', - src: '/events/blocks/adobe-connect/asset/Frame.svg', + src: '/events/blocks/adobe-connect/asset/Cross.svg', alt: 'Close overlay', }, ); diff --git a/events/blocks/adobe-connect/asset/Frame.svg b/events/blocks/adobe-connect/asset/Cross.svg similarity index 100% rename from events/blocks/adobe-connect/asset/Frame.svg rename to events/blocks/adobe-connect/asset/Cross.svg From 80d963738f78a01c632dd936871aa0eccf1d01dc Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Thu, 24 Jul 2025 18:14:33 +0530 Subject: [PATCH 69/93] adding right watch point --- rs/360-KCI-804/images/mktoTestFormConfig.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rs/360-KCI-804/images/mktoTestFormConfig.js b/rs/360-KCI-804/images/mktoTestFormConfig.js index e27a186a..eb81385e 100644 --- a/rs/360-KCI-804/images/mktoTestFormConfig.js +++ b/rs/360-KCI-804/images/mktoTestFormConfig.js @@ -50,7 +50,7 @@ if ( var BASE_URL = "https://engage.marketo.com"; var MUNCHKIN_ID = "360-KCI-804"; var resourceLocation = ".chrono-box"; - var resourceWatch = '.chrono-box'; + var resourceWatch = 'main .section .chrono-box'; let mczFrm_mkto_testing_loader = () => { let cssFast = ` button[daa-ll="Join the event-1--"] { @@ -307,8 +307,10 @@ if ( mczFrm_sendMessage("reg_submitted", "root.program_profile"); const resource = document.querySelector(resourceWatch); - if(resource) { + if (resource) { resource.setAttribute('data-mcz-dl-status', 'active'); + } else { + console.log('resourceWatch not found', resourceWatch); } }; From 87043b1b140d5296e5ffc4c2dcd0ccadf5cd48ef Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Thu, 24 Jul 2025 18:23:42 +0530 Subject: [PATCH 70/93] minor fix --- rs/360-KCI-804/images/mktoTestFormConfig.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/rs/360-KCI-804/images/mktoTestFormConfig.js b/rs/360-KCI-804/images/mktoTestFormConfig.js index eb81385e..244d0349 100644 --- a/rs/360-KCI-804/images/mktoTestFormConfig.js +++ b/rs/360-KCI-804/images/mktoTestFormConfig.js @@ -851,17 +851,21 @@ if ( //* //* let maxTries = 1000; - let checkResourceLocation = async () => { + let checkResourceLocation = () => { if (maxTries <= 0) { console.log("maxTries reached", maxTries); return; } maxTries--; if (document.querySelector(resourceWatch)) { - mczFrm_mkto_testing_loader(); + setTimeout(() => { + mczFrm_mkto_testing_loader(); + }, 5000); } else { - await new Promise((resolve) => setTimeout(resolve, 25)); - checkResourceLocation(); + // await new Promise((resolve) => setTimeout(resolve, 25)); + setTimeout(() => { + checkResourceLocation(); + }, 500); } }; checkResourceLocation(); From 1be2c2af094900e2d564c9e403c2da63750651ea Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Thu, 24 Jul 2025 18:59:14 +0530 Subject: [PATCH 71/93] adding minor fix --- events/blocks/chrono-box/chrono-box.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/events/blocks/chrono-box/chrono-box.js b/events/blocks/chrono-box/chrono-box.js index 4510cedc..7fd96685 100644 --- a/events/blocks/chrono-box/chrono-box.js +++ b/events/blocks/chrono-box/chrono-box.js @@ -177,7 +177,7 @@ export default async function init(el) { if (window.mcz_marketoForm_pref?.form?.success?.type === 'adobe_connect') { const eventUrl = window.mcz_marketoForm_pref?.form?.success?.content; setMetadata('adobe-connect-url', eventUrl); - metadataStore.set('marketo-next', ''); + metadataStore.set('marketo-next', 'adobe-connect'); } } From 3973d26ef29eb7d92bc20932c6bda07d4e86f829 Mon Sep 17 00:00:00 2001 From: ambalika91 Date: Fri, 25 Jul 2025 13:07:27 +0530 Subject: [PATCH 72/93] css formatting --- events/blocks/adobe-connect/adobe-connect.css | 263 +++++++++--------- 1 file changed, 133 insertions(+), 130 deletions(-) diff --git a/events/blocks/adobe-connect/adobe-connect.css b/events/blocks/adobe-connect/adobe-connect.css index 818cc499..d3fd283d 100644 --- a/events/blocks/adobe-connect/adobe-connect.css +++ b/events/blocks/adobe-connect/adobe-connect.css @@ -2,153 +2,156 @@ width: 100%; padding: 0; margin: 0; -} -.adobe-connect .fullwidth { + .fullwidth { width: 100%; height: 900px; } -.adobe-connect button { - font-size: var(--type-body-s-size); - background-color: var(--link-color); - min-width: 114px; - height: 40px; - line-height: 20px; - padding: 9px 16px; - border: 0; - border-radius: 24px; - color: #fff; - font-weight: 700; - box-shadow: none; - margin: 0 auto; - cursor: pointer; - transition: background-color 0.13s, color 0.13s; -} + button { + font-size: var(--type-body-s-size); + background-color: var(--link-color); + min-width: 114px; + height: 40px; + line-height: 20px; + padding: 9px 16px; + border: 0; + border-radius: 24px; + color: #fff; + font-weight: 700; + box-shadow: none; + margin: 0 auto; + cursor: pointer; + transition: background-color 0.13s, color 0.13s; + } -.adobe-connect .hidden { - visibility: hidden !important; - opacity: 0 !important; -} + .hidden { + visibility: hidden !important; + opacity: 0 !important; + } -/* Overlay background */ -.iframe-overlay { - position: fixed; - inset: 0; - background: rgba(0, 0, 0, 85%); - color: #fff; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - z-index: 9999; - font-family: inherit; - pointer-events: auto; - padding: 10px; - gap: 16px; - flex-shrink: 0; - margin : 0; -} + /* Overlay background */ + .iframe-overlay { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 85%); + color: #fff; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + z-index: 9999; + font-family: inherit; + pointer-events: auto; + padding: 10px; + gap: 16px; + flex-shrink: 0; + margin: 0; -/* Close button */ -.iframe-overlay .overlay-close-btn { - display: flex; - width: 22px; - height: 22px; - align-items: flex-start; - position: absolute; - right: 32px; - top: 33px; -} + /* Close button */ + .overlay-close-btn { + display: flex; + width: 22px; + height: 22px; + align-items: flex-start; + position: absolute; + right: 32px; + top: 33px; + } -/* Heading */ -.iframe-overlay .overlay-heading, -.iframe-overlay .overlay-heading-yrs { - font-weight: 700; - text-align: center; - line-height: 125%; - font-style: normal; - color: #fff; - font-size: 24px; - align-self: stretch; - margin: 0; -} + /* Heading */ + .overlay-heading, + .overlay-heading-yrs { + font-weight: 700; + text-align: center; + line-height: 125%; + font-style: normal; + color: #fff; + font-size: 24px; + align-self: stretch; + margin: 0; + } -/* Subheading */ -.iframe-overlay .overlay-subheading { - width: 245px; - color: #FFF; - text-align: center; - font-size: 16px; - font-weight: 700; - line-height: 125%; -} + /* Subheading */ + .overlay-subheading { + width: 245px; + color: #FFF; + text-align: center; + font-size: 16px; + font-weight: 700; + line-height: 125%; + } -/* Illustration */ -.iframe-overlay .overlay-illustration { - margin: 40px 0 40px 0; - display: flex; - justify-content: center; -} + /* Illustration */ + .overlay-illustration { + margin: 40px 0 40px 0; + display: flex; + justify-content: center; + } -/* Best viewed in landscape */ -.iframe-overlay .overlay-landscape { - height: 22px; - align-self: stretch; - color: #FFF; - text-align: center; - font-size: 18px; - font-style: normal; - font-weight: 700; - line-height: 125%; /* 22.5px */ -} + /* Best viewed in landscape */ + .overlay-landscape { + height: 22px; + align-self: stretch; + color: #FFF; + text-align: center; + font-size: 18px; + font-style: normal; + font-weight: 700; + line-height: 125%; + /* 22.5px */ + } -/* Rotate your phone message */ -.iframe-overlay .overlay-rotate-msg { - align-self: stretch; - color: #FFF; - text-align: center; - font-size: 12px; - font-style: normal; - font-weight: 400; - line-height: 150%; /* 18px */ -} + /* Rotate your phone message */ + .overlay-rotate-msg { + align-self: stretch; + color: #FFF; + text-align: center; + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 150%; + /* 18px */ + } -/* Continue to webinar button */ -.iframe-overlay .overlay-continue-btn { - height: 50px; - background:#3B63FB; - color: #FFF; - text-align: center; - font-size: 19px; - font-style: normal; - font-weight: 700; - padding: 12px 24px 14px 24px; - border-radius: 100px; - line-height: 24px; /* 126.316% */ - margin-top: 40px; -} + /* Continue to webinar button */ + .overlay-continue-btn { + height: 50px; + background: #3B63FB; + color: #FFF; + text-align: center; + font-size: 19px; + font-style: normal; + font-weight: 700; + padding: 12px 24px 14px 24px; + border-radius: 100px; + line-height: 24px; + /* 126.316% */ + margin-top: 40px; + } -@media only screen and (orientation: portrait) { - .iframe-overlay .overlay-heading-yrs { - display: none; - } -} + @media only screen and (orientation: portrait) { + .overlay-heading-yrs { + display: none; + } + } -@media only screen and (orientation: landscape){ - .iframe-overlay .overlay-heading { - display: none; - } + @media only screen and (orientation: landscape) { + .overlay-heading { + display: none; + } - .iframe-overlay .overlay-subheading { - display: none; - } + .overlay-subheading { + display: none; + } - .iframe-overlay .overlay-landscape { - display: none; - } - - .iframe-overlay .overlay-rotate-msg { - display: none; + .overlay-landscape { + display: none; + } + + .overlay-rotate-msg { + display: none; + } + } } } From 38ceba02b20db06e3851428fb995e199353f1596 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Fri, 25 Jul 2025 18:34:25 +0530 Subject: [PATCH 73/93] marketo block --- events/blocks/marketo-form/marketo-form.css | 50 +++++++++++++++++++++ events/blocks/marketo-form/marketo-form.js | 12 +++++ rs/360-KCI-804/images/mktoTestFormConfig.js | 46 +++++++++---------- 3 files changed, 85 insertions(+), 23 deletions(-) create mode 100644 events/blocks/marketo-form/marketo-form.css create mode 100644 events/blocks/marketo-form/marketo-form.js diff --git a/events/blocks/marketo-form/marketo-form.css b/events/blocks/marketo-form/marketo-form.css new file mode 100644 index 00000000..5ed320a1 --- /dev/null +++ b/events/blocks/marketo-form/marketo-form.css @@ -0,0 +1,50 @@ +.marketo-form { + width: 100%; + margin: 0 auto; + padding: 20px 0; +} + +.marketo-form-container { + position: relative; + width: 100%; + max-width: 800px; + margin: 0 auto; + background: #fff; + border-radius: 8px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + overflow: hidden; +} + +.marketo-form-iframe { + width: 100%; + min-height: 500px; + border: none; + display: block; +} + +.marketo-form-loading { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + padding: 20px; + background: rgba(255, 255, 255, 0.9); + border-radius: 4px; + font-size: 16px; + color: #666; + z-index: 1; +} + +@media (max-width: 768px) { + .marketo-form { + padding: 10px 0; + } + + .marketo-form-container { + margin: 0 10px; + } + + .marketo-form-iframe { + min-height: 400px; + } +} \ No newline at end of file diff --git a/events/blocks/marketo-form/marketo-form.js b/events/blocks/marketo-form/marketo-form.js new file mode 100644 index 00000000..e332963c --- /dev/null +++ b/events/blocks/marketo-form/marketo-form.js @@ -0,0 +1,12 @@ +// import { LIBS } from '../../scripts/utils.js'; +import { checkResourceLocation } from '../../../rs/360-KCI-804/images/mktoTestFormConfig.js'; + +// const { createTag, getMetadata } = await import(`${LIBS}/utils/utils.js`); + + + +export default async function init(el) { + const resourceLocation = '.chrono-box'; + const resourceWatch = 'main .section .chrono-box'; + await checkResourceLocation(el, resourceWatch, resourceLocation); +} \ No newline at end of file diff --git a/rs/360-KCI-804/images/mktoTestFormConfig.js b/rs/360-KCI-804/images/mktoTestFormConfig.js index 244d0349..575f8f29 100644 --- a/rs/360-KCI-804/images/mktoTestFormConfig.js +++ b/rs/360-KCI-804/images/mktoTestFormConfig.js @@ -49,9 +49,9 @@ if ( var BASE_URL = "https://engage.marketo.com"; var MUNCHKIN_ID = "360-KCI-804"; - var resourceLocation = ".chrono-box"; - var resourceWatch = 'main .section .chrono-box'; - let mczFrm_mkto_testing_loader = () => { + // var resourceLocation = ".chrono-box"; + // var resourceWatch = 'main .section .chrono-box'; + var mczFrm_mkto_testing_loader = () => { let cssFast = ` button[daa-ll="Join the event-1--"] { visibility: hidden !important; @@ -850,26 +850,26 @@ if ( //* //* //* - let maxTries = 1000; - let checkResourceLocation = () => { - if (maxTries <= 0) { - console.log("maxTries reached", maxTries); - return; - } - maxTries--; - if (document.querySelector(resourceWatch)) { - setTimeout(() => { - mczFrm_mkto_testing_loader(); - }, 5000); - } else { - // await new Promise((resolve) => setTimeout(resolve, 25)); - setTimeout(() => { - checkResourceLocation(); - }, 500); - } - }; - checkResourceLocation(); } // ## -// ## \ No newline at end of file +// ## + +let maxTries = 1000; +export function checkResourceLocation(el, resourceWatch, resourceLocation) { + if (maxTries <= 0) { + console.log("maxTries reached", maxTries); + return; + } + maxTries--; + if (document.querySelector(resourceWatch)) { + setTimeout(() => { + mczFrm_mkto_testing_loader(); + }, 5000); + } else { + // await new Promise((resolve) => setTimeout(resolve, 25)); + setTimeout(() => { + checkResourceLocation(el, resourceWatch, resourceLocation); + }, 500); + } +}; \ No newline at end of file From b607f82b481637db66d2a75ea2b3a070615b8ed4 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Mon, 28 Jul 2025 15:32:18 +0530 Subject: [PATCH 74/93] updating the mkto form --- events/blocks/marketo-form/marketo-form.js | 6 +- rs/360-KCI-804/images/mktoTestFormConfig.js | 167 ++++++++++++++------ 2 files changed, 123 insertions(+), 50 deletions(-) diff --git a/events/blocks/marketo-form/marketo-form.js b/events/blocks/marketo-form/marketo-form.js index e332963c..94c793f8 100644 --- a/events/blocks/marketo-form/marketo-form.js +++ b/events/blocks/marketo-form/marketo-form.js @@ -1,12 +1,10 @@ // import { LIBS } from '../../scripts/utils.js'; -import { checkResourceLocation } from '../../../rs/360-KCI-804/images/mktoTestFormConfig.js'; +import { CheckResourceLocation } from '../../../rs/360-KCI-804/images/mktoTestFormConfig.js'; // const { createTag, getMetadata } = await import(`${LIBS}/utils/utils.js`); - - export default async function init(el) { const resourceLocation = '.chrono-box'; const resourceWatch = 'main .section .chrono-box'; - await checkResourceLocation(el, resourceWatch, resourceLocation); + await CheckResourceLocation(el, resourceWatch, resourceLocation); } \ No newline at end of file diff --git a/rs/360-KCI-804/images/mktoTestFormConfig.js b/rs/360-KCI-804/images/mktoTestFormConfig.js index 575f8f29..2443adec 100644 --- a/rs/360-KCI-804/images/mktoTestFormConfig.js +++ b/rs/360-KCI-804/images/mktoTestFormConfig.js @@ -50,8 +50,8 @@ if ( var BASE_URL = "https://engage.marketo.com"; var MUNCHKIN_ID = "360-KCI-804"; // var resourceLocation = ".chrono-box"; - // var resourceWatch = 'main .section .chrono-box'; - var mczFrm_mkto_testing_loader = () => { + // var resourceWatch = "main .section .chrono-box"; + let mczFrm_mkto_testing_loader = (el, resourceWatch, resourceLocation) => { let cssFast = ` button[daa-ll="Join the event-1--"] { visibility: hidden !important; @@ -297,6 +297,15 @@ if ( final_url = event_url.trim(); } + let adobe_connect_status = + window.mcz_marketoForm_pref?.program?.event?.adobe_connect?.status || null; + if (adobe_connect_status == null) { + adobe_connect_status = {}; + } + adobe_connect_status.overall = "active"; + + mczFrm_saveSnapshot(); + if (document.querySelector(".marketo-form-wrapper")) { document.querySelector(".marketo-form-wrapper").classList.add("hide"); } @@ -304,14 +313,6 @@ if ( document.querySelector('.adobe-connect button[daa-ll*="Join"]').click(); } console.log("adobe_connect_event", final_url); - mczFrm_sendMessage("reg_submitted", "root.program_profile"); - - const resource = document.querySelector(resourceWatch); - if (resource) { - resource.setAttribute('data-mcz-dl-status', 'active'); - } else { - console.log('resourceWatch not found', resourceWatch); - } }; // @@ -337,17 +338,23 @@ if ( } function mczFrm_currentMarketoTime() { - let serverTimeOffset; - let serverTimeRaw = mcz_marketoForm_pref?.program?.marketo_asset?.time?.systemDateTime || null; + let serverTimeOffset = mcz_marketoForm_pref?.program?.marketo_asset?.time?.offset || null; try { - if (serverTimeRaw) { - let serverTimeInitial = new Date(serverTimeRaw).getTime(); - if (!isNaN(serverTimeInitial)) { - let clientTimeInitial = new Date().getTime(); - serverTimeOffset = serverTimeInitial - clientTimeInitial; + if (serverTimeOffset == null) { + let serverTimeRaw = + mcz_marketoForm_pref?.program?.marketo_asset?.time?.systemDateTime || null; + if (serverTimeRaw) { + let serverTimeInitial = new Date(serverTimeRaw).getTime(); + if (!isNaN(serverTimeInitial)) { + let clientTimeInitial = new Date().getTime() + serverTimeOffset; + serverTimeOffset = serverTimeInitial - clientTimeInitial; + mcz_marketoForm_pref.program.marketo_asset.time.offset = serverTimeOffset; + } + } else { + serverTimeOffset = 0; } } else { - serverTimeOffset = 0; + serverTimeOffset = parseInt(serverTimeOffset) || 0; } } catch (e) { console.warn("Error getting server time offset", e); @@ -372,11 +379,12 @@ if ( } let adobe_connect_status = base?.program?.event?.adobe_connect?.status || null; - if (adobe_connect_status == null) { adobe_connect_status = {}; } + general_status = adobe_connect_status.overall || "register"; + let endDate = new Date(endDateTime); let startDate = new Date(startDateTime); let nowDate = new Date(nowDateTime); @@ -399,7 +407,6 @@ if ( adobe_connect_status.has_started = false; adobe_connect_status.is_reg_open = false; adobe_connect_status.is_reg_closed = false; - general_status = "register"; if (timeUntilInterval) { clearInterval(timeUntilInterval); @@ -472,7 +479,7 @@ if ( adobe_connect_status.has_ended = false; adobe_connect_status.is_reg_open = true; adobe_connect_status.is_reg_closed = false; - general_status = "live"; + general_status = "active"; stillReview = false; } } @@ -485,7 +492,7 @@ if ( adobe_connect_status.has_started = true; adobe_connect_status.is_reg_open = false; adobe_connect_status.is_reg_closed = true; - general_status = "live"; + general_status = "active"; stillReview = false; } } @@ -565,7 +572,7 @@ if ( let munchkinId = MUNCHKIN_ID || "360-KCI-804"; addMunchkin(munchkinId, pageFromEventId, mktToken); let programIDOnly = pageFromEventId.replace(/[^0-9]/g, ""); - let programfromStorage = await mczFrm_aquireFromStorage(`ev__${programIDOnly}`); + let programfromStorage = await mczFrm_aquireFromStorage(`pr_${programIDOnly}_`); if (programfromStorage) { console.log("MCZ Form, Updating DL from storage:", programfromStorage); mczFrm_updateDL(programfromStorage); @@ -699,12 +706,48 @@ if ( localStorage.setItem(saveAlias, dataStr); } + console.log("MCZ RefData: Saved message:", message); + mczFrm_saveRefs(saveAlias, refStorageKey); } catch (storageError) { console.warn("Storage error:", storageError); } } + async function mczFrm_saveSnapshot(target_path = "root.program") { + let snapshot = {}; + let base = window?.mcz_marketoForm_pref || null; + if (base == null) { + console.log("No base found, skipping snapshot."); + return; + } + + let pageFromEventId = base?.program?.event?.id || ""; + let programIDOnly = pageFromEventId?.replace(/[^0-9]/g, "") || ""; + if (programIDOnly == "") { + console.log("No event id found, skipping snapshot."); + return; + } + + if (target_path == "root.program_profile") { + snapshot = base.program_profile; + } else if (target_path == "root.profile") { + snapshot = base.profile; + } else if (target_path == "root.form") { + snapshot = base.form; + } else if (target_path == "root.program") { + snapshot = base.program; + } else if (target_path == "root.program.event") { + snapshot = base.program.event; + } + + mczFrm_saveMsg({ + alias: `pr_${programIDOnly}_`, + location: "local", + data: JSON.parse(JSON.stringify(snapshot)), + }); + } + window.addEventListener("message", (event) => { let config = { allowedOrigins: ["https://engage.adobe.com", "https://business.adobe.com"], @@ -738,6 +781,32 @@ if ( } }); + function crawlAndUpdateObject(thisObject = null, targetObject = null) { + if (thisObject == null || targetObject == null) { + console.warn("No object to crawl or update"); + return; + } + let this_data = JSON.parse(JSON.stringify(thisObject)); + for (let key in this_data) { + if (targetObject.hasOwnProperty(key)) { + if (this_data[key] != null && this_data[key] != "" && this_data[key] != 0) { + if (typeof this_data[key] == "object") { + crawlAndUpdateObject(this_data[key], targetObject[key]); + } else { + if ( + targetObject[key] == null || + targetObject[key] == "" || + targetObject[key] == 0 || + targetObject[key] == "NULL" + ) { + targetObject[key] = this_data[key]; + } + } + } + } + } + } + function mczFrm_updateDL(data = null) { if (data == null) { return; @@ -752,17 +821,23 @@ if ( let this_data = JSON.parse(JSON.stringify(data?.data)); if (targetPath == "root.program_profile") { window.mcz_marketoForm_pref.program_profile = this_data; + //crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.program_profile); } else if (targetPath == "root.profile") { - window.mcz_marketoForm_pref.profile = this_data; + //window.mcz_marketoForm_pref.profile = this_data; + crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.profile); } else if (targetPath == "root.form") { window.mcz_marketoForm_pref.form = this_data; + //crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.form); } else if (targetPath == "root.profile.acc") { window.mcz_marketoForm_pref.profile.acc = this_data; + //crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.profile.acc); } else if (targetPath == "root.program") { window.mcz_marketoForm_pref.program = this_data; + //crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.program); program_type = this_data?.type || "default"; } else if (targetPath == "root.program.event") { window.mcz_marketoForm_pref.program.event = this_data; + //crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.program.event); program_type = this_data?.type || "default"; } @@ -771,7 +846,7 @@ if ( if (window.mcz_marketoForm_pref?.program?.event?.type == "adobe_connect") { program_type = "adobe_connect"; program_status = - window.mcz_marketoForm_pref?.program?.event?.adobe_connect?.status?.overall || "default"; + window.mcz_marketoForm_pref?.program?.event?.adobe_connect?.status?.overall || "pending"; } } @@ -797,23 +872,24 @@ if ( mczFrm_statusLbls(program_type, program_status); } - function mczFrm_sendMessage(msgName = null, targetPath = "root.program", data = {}) { + function mczFrm_sendMessage(targetPath = "root.program", data = {}) { let iframe = document.getElementById("mcz-marketo-program-iframe"); if (iframe) { - let message = { - type: "mcz_marketoForm_pref_sync", - data: { + if (JSON.stringify(data) == "{}") { + data = { + type: "mcz_marketoForm_pref_sync", target_path: targetPath, - data: data, - }, - }; + }; + } - iframe.contentWindow.postMessage(message, "https://engage.adobe.com"); + iframe.contentWindow.postMessage(data, "https://engage.adobe.com"); } else { console.warn("No iframe found"); } } + window.mczFrm_sendMessage = mczFrm_sendMessage; + //* //* //* @@ -850,26 +926,25 @@ if ( //* //* //* -} // ## // ## - let maxTries = 1000; -export function checkResourceLocation(el, resourceWatch, resourceLocation) { +export function CheckResourceLocation(el, resourceWatch, resourceLocation) { if (maxTries <= 0) { console.log("maxTries reached", maxTries); return; } maxTries--; - if (document.querySelector(resourceWatch)) { - setTimeout(() => { - mczFrm_mkto_testing_loader(); - }, 5000); - } else { - // await new Promise((resolve) => setTimeout(resolve, 25)); - setTimeout(() => { - checkResourceLocation(el, resourceWatch, resourceLocation); - }, 500); - } + if (document.querySelector(resourceWatch)) { + setTimeout(() => { + console.log("Resource found, loading..."); + mczFrm_mkto_testing_loader(el, resourceWatch, resourceLocation); + }, 1000); + } else { + setTimeout(() => { + console.log("Resource not found, checking again..."); + checkResourceLocation(el, resourceWatch, resourceLocation); + }, 20); + } }; \ No newline at end of file From 3d0de68cd8efcec3e5d2b0f12d07256760578c57 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Mon, 28 Jul 2025 16:30:20 +0530 Subject: [PATCH 75/93] adding new element --- .../marketo-form-ui/marketo-form-ui.css | 50 +++++++++++++++++++ .../blocks/marketo-form-ui/marketo-form-ui.js | 11 ++++ events/blocks/marketo-form/marketo-form.js | 6 +-- 3 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 events/blocks/marketo-form-ui/marketo-form-ui.css create mode 100644 events/blocks/marketo-form-ui/marketo-form-ui.js diff --git a/events/blocks/marketo-form-ui/marketo-form-ui.css b/events/blocks/marketo-form-ui/marketo-form-ui.css new file mode 100644 index 00000000..5ed320a1 --- /dev/null +++ b/events/blocks/marketo-form-ui/marketo-form-ui.css @@ -0,0 +1,50 @@ +.marketo-form { + width: 100%; + margin: 0 auto; + padding: 20px 0; +} + +.marketo-form-container { + position: relative; + width: 100%; + max-width: 800px; + margin: 0 auto; + background: #fff; + border-radius: 8px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + overflow: hidden; +} + +.marketo-form-iframe { + width: 100%; + min-height: 500px; + border: none; + display: block; +} + +.marketo-form-loading { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + padding: 20px; + background: rgba(255, 255, 255, 0.9); + border-radius: 4px; + font-size: 16px; + color: #666; + z-index: 1; +} + +@media (max-width: 768px) { + .marketo-form { + padding: 10px 0; + } + + .marketo-form-container { + margin: 0 10px; + } + + .marketo-form-iframe { + min-height: 400px; + } +} \ No newline at end of file diff --git a/events/blocks/marketo-form-ui/marketo-form-ui.js b/events/blocks/marketo-form-ui/marketo-form-ui.js new file mode 100644 index 00000000..9217d0be --- /dev/null +++ b/events/blocks/marketo-form-ui/marketo-form-ui.js @@ -0,0 +1,11 @@ +import { LIBS } from '../../scripts/utils.js'; + +const { createTag } = await import(`${LIBS}/utils/utils.js`); + +export default async function init(el) { + const rows = Array.from(el.children); + const idName = `#${rows[0].textContent.trim().toLowerCase()}`; + + el.innerHTML = ''; + createTag('div', { id: idName, class: 'marketo-form-ui' }, '', { parent: el }); +} diff --git a/events/blocks/marketo-form/marketo-form.js b/events/blocks/marketo-form/marketo-form.js index 94c793f8..4b8dabfb 100644 --- a/events/blocks/marketo-form/marketo-form.js +++ b/events/blocks/marketo-form/marketo-form.js @@ -1,10 +1,8 @@ -// import { LIBS } from '../../scripts/utils.js'; import { CheckResourceLocation } from '../../../rs/360-KCI-804/images/mktoTestFormConfig.js'; -// const { createTag, getMetadata } = await import(`${LIBS}/utils/utils.js`); - export default async function init(el) { - const resourceLocation = '.chrono-box'; + const rows = Array.from(el.children); + const resourceLocation = `#${rows[0].textContent.trim().toLowerCase()}`; const resourceWatch = 'main .section .chrono-box'; await CheckResourceLocation(el, resourceWatch, resourceLocation); } \ No newline at end of file From 7ac4c41a40e9a69edbb75edece133ab6fb7b3a0f Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Mon, 28 Jul 2025 16:58:38 +0530 Subject: [PATCH 76/93] UI enhancements --- .../marketo-form-ui/marketo-form-ui.css | 50 ------------------- .../blocks/marketo-form-ui/marketo-form-ui.js | 2 +- events/blocks/marketo-form/marketo-form.css | 50 ------------------- events/blocks/marketo-form/marketo-form.js | 2 + rs/360-KCI-804/images/mktoTestFormConfig.js | 15 ++++-- 5 files changed, 14 insertions(+), 105 deletions(-) delete mode 100644 events/blocks/marketo-form-ui/marketo-form-ui.css delete mode 100644 events/blocks/marketo-form/marketo-form.css diff --git a/events/blocks/marketo-form-ui/marketo-form-ui.css b/events/blocks/marketo-form-ui/marketo-form-ui.css deleted file mode 100644 index 5ed320a1..00000000 --- a/events/blocks/marketo-form-ui/marketo-form-ui.css +++ /dev/null @@ -1,50 +0,0 @@ -.marketo-form { - width: 100%; - margin: 0 auto; - padding: 20px 0; -} - -.marketo-form-container { - position: relative; - width: 100%; - max-width: 800px; - margin: 0 auto; - background: #fff; - border-radius: 8px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); - overflow: hidden; -} - -.marketo-form-iframe { - width: 100%; - min-height: 500px; - border: none; - display: block; -} - -.marketo-form-loading { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - padding: 20px; - background: rgba(255, 255, 255, 0.9); - border-radius: 4px; - font-size: 16px; - color: #666; - z-index: 1; -} - -@media (max-width: 768px) { - .marketo-form { - padding: 10px 0; - } - - .marketo-form-container { - margin: 0 10px; - } - - .marketo-form-iframe { - min-height: 400px; - } -} \ No newline at end of file diff --git a/events/blocks/marketo-form-ui/marketo-form-ui.js b/events/blocks/marketo-form-ui/marketo-form-ui.js index 9217d0be..a612fee0 100644 --- a/events/blocks/marketo-form-ui/marketo-form-ui.js +++ b/events/blocks/marketo-form-ui/marketo-form-ui.js @@ -4,7 +4,7 @@ const { createTag } = await import(`${LIBS}/utils/utils.js`); export default async function init(el) { const rows = Array.from(el.children); - const idName = `#${rows[0].textContent.trim().toLowerCase()}`; + const idName = `${rows[0].textContent.trim().toLowerCase()}`; el.innerHTML = ''; createTag('div', { id: idName, class: 'marketo-form-ui' }, '', { parent: el }); diff --git a/events/blocks/marketo-form/marketo-form.css b/events/blocks/marketo-form/marketo-form.css deleted file mode 100644 index 5ed320a1..00000000 --- a/events/blocks/marketo-form/marketo-form.css +++ /dev/null @@ -1,50 +0,0 @@ -.marketo-form { - width: 100%; - margin: 0 auto; - padding: 20px 0; -} - -.marketo-form-container { - position: relative; - width: 100%; - max-width: 800px; - margin: 0 auto; - background: #fff; - border-radius: 8px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); - overflow: hidden; -} - -.marketo-form-iframe { - width: 100%; - min-height: 500px; - border: none; - display: block; -} - -.marketo-form-loading { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - padding: 20px; - background: rgba(255, 255, 255, 0.9); - border-radius: 4px; - font-size: 16px; - color: #666; - z-index: 1; -} - -@media (max-width: 768px) { - .marketo-form { - padding: 10px 0; - } - - .marketo-form-container { - margin: 0 10px; - } - - .marketo-form-iframe { - min-height: 400px; - } -} \ No newline at end of file diff --git a/events/blocks/marketo-form/marketo-form.js b/events/blocks/marketo-form/marketo-form.js index 4b8dabfb..6d65ad81 100644 --- a/events/blocks/marketo-form/marketo-form.js +++ b/events/blocks/marketo-form/marketo-form.js @@ -4,5 +4,7 @@ export default async function init(el) { const rows = Array.from(el.children); const resourceLocation = `#${rows[0].textContent.trim().toLowerCase()}`; const resourceWatch = 'main .section .chrono-box'; + + el.innerHTML = ''; await CheckResourceLocation(el, resourceWatch, resourceLocation); } \ No newline at end of file diff --git a/rs/360-KCI-804/images/mktoTestFormConfig.js b/rs/360-KCI-804/images/mktoTestFormConfig.js index 2443adec..c71ac0a1 100644 --- a/rs/360-KCI-804/images/mktoTestFormConfig.js +++ b/rs/360-KCI-804/images/mktoTestFormConfig.js @@ -49,9 +49,7 @@ if ( var BASE_URL = "https://engage.marketo.com"; var MUNCHKIN_ID = "360-KCI-804"; - // var resourceLocation = ".chrono-box"; - // var resourceWatch = "main .section .chrono-box"; - let mczFrm_mkto_testing_loader = (el, resourceWatch, resourceLocation) => { + let mczFrm_mkto_testing_loader = (el, resourceLocation) => { let cssFast = ` button[daa-ll="Join the event-1--"] { visibility: hidden !important; @@ -313,6 +311,15 @@ if ( document.querySelector('.adobe-connect button[daa-ll*="Join"]').click(); } console.log("adobe_connect_event", final_url); + + // To lookup a resource which has attribute 'data-mcz-dl-status'. + // Required for loading adobe connect player + const resource = document.querySelector('[data-mcz-dl-status]'); + if (resource) { + resource.setAttribute('data-mcz-dl-status', 'active'); + } else { + console.log('no resource with attribute data-mcz-dl-status found'); + } }; // @@ -939,7 +946,7 @@ export function CheckResourceLocation(el, resourceWatch, resourceLocation) { if (document.querySelector(resourceWatch)) { setTimeout(() => { console.log("Resource found, loading..."); - mczFrm_mkto_testing_loader(el, resourceWatch, resourceLocation); + mczFrm_mkto_testing_loader(el, resourceLocation); }, 1000); } else { setTimeout(() => { From d4f7b71d2f6e9fafb9da9431cd0bd543ebd00038 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Mon, 28 Jul 2025 17:02:17 +0530 Subject: [PATCH 77/93] minor fixes --- rs/360-KCI-804/images/mktoTestFormConfig.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rs/360-KCI-804/images/mktoTestFormConfig.js b/rs/360-KCI-804/images/mktoTestFormConfig.js index c71ac0a1..62a36728 100644 --- a/rs/360-KCI-804/images/mktoTestFormConfig.js +++ b/rs/360-KCI-804/images/mktoTestFormConfig.js @@ -933,6 +933,7 @@ if ( //* //* //* +} // ## // ## @@ -951,7 +952,7 @@ export function CheckResourceLocation(el, resourceWatch, resourceLocation) { } else { setTimeout(() => { console.log("Resource not found, checking again..."); - checkResourceLocation(el, resourceWatch, resourceLocation); + CheckResourceLocation(el, resourceWatch, resourceLocation); }, 20); } }; \ No newline at end of file From 29dd436fe5dff15cec3a531bd04ab53255aefa78 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Mon, 28 Jul 2025 17:04:41 +0530 Subject: [PATCH 78/93] minor correction --- rs/360-KCI-804/images/mktoTestFormConfig.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rs/360-KCI-804/images/mktoTestFormConfig.js b/rs/360-KCI-804/images/mktoTestFormConfig.js index 62a36728..413da89c 100644 --- a/rs/360-KCI-804/images/mktoTestFormConfig.js +++ b/rs/360-KCI-804/images/mktoTestFormConfig.js @@ -49,7 +49,7 @@ if ( var BASE_URL = "https://engage.marketo.com"; var MUNCHKIN_ID = "360-KCI-804"; - let mczFrm_mkto_testing_loader = (el, resourceLocation) => { + var mczFrm_mkto_testing_loader = (el, resourceLocation) => { let cssFast = ` button[daa-ll="Join the event-1--"] { visibility: hidden !important; From 38b5133cd5e796a48fd7a5e6f36315740820fbd5 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Mon, 28 Jul 2025 21:01:54 +0530 Subject: [PATCH 79/93] custom event support for marketo form complete --- events/blocks/adobe-connect/adobe-connect.js | 14 ---- events/blocks/chrono-box/chrono-box.js | 46 ------------- events/blocks/marketo-form/marketo-form.js | 67 ++++++++++++++++++- .../plugins/metadata/plugin.js | 17 +++++ 4 files changed, 83 insertions(+), 61 deletions(-) diff --git a/events/blocks/adobe-connect/adobe-connect.js b/events/blocks/adobe-connect/adobe-connect.js index a3225d06..ca3db28f 100644 --- a/events/blocks/adobe-connect/adobe-connect.js +++ b/events/blocks/adobe-connect/adobe-connect.js @@ -2,15 +2,6 @@ import { LIBS, getMetadata } from '../../scripts/utils.js'; const { createTag } = await import(`${LIBS}/utils/utils.js`); -function validateUrl(url) { - try { - new URL(url); - return true; - } catch (_) { - return false; - } -} - function addParams(searchParams, params, key, value) { if (params.has(key)) { searchParams[key] = params.get(key); @@ -40,7 +31,6 @@ function getSearchParamsFromCurrentUrl() { export default async function init(el) { const h2 = el.querySelector('h2'); let url = h2?.textContent; - el.setAttribute('data-mcz-dl-status', 'loading'); h2.remove(); @@ -53,10 +43,6 @@ export default async function init(el) { return; } - // if (validateUrl(window.join_url)) { - // url = window.join_url; - // console.log("join_url in Window", window.join_url); - // } url = addSearchParams(url, searchParams); // Create overlay diff --git a/events/blocks/chrono-box/chrono-box.js b/events/blocks/chrono-box/chrono-box.js index 7fd96685..db56ab19 100644 --- a/events/blocks/chrono-box/chrono-box.js +++ b/events/blocks/chrono-box/chrono-box.js @@ -172,50 +172,4 @@ export default async function init(el) { el.classList.add('error'); }); }; - - function mczMarketoFormAdobeConnectEvent() { - if (window.mcz_marketoForm_pref?.form?.success?.type === 'adobe_connect') { - const eventUrl = window.mcz_marketoForm_pref?.form?.success?.content; - setMetadata('adobe-connect-url', eventUrl); - metadataStore.set('marketo-next', 'adobe-connect'); - } - } - - // Debounce function to limit rapid calls - function debounce(func, wait) { - let timeout; - return function executedFunction(...args) { - const later = () => { - clearTimeout(timeout); - func(...args); - }; - clearTimeout(timeout); - timeout = setTimeout(later, wait); - }; - } - - // Debounced callback for observer - const debouncedCallback = debounce(() => { - const status = el.getAttribute('data-mcz-dl-status'); - console.log( - 'Attribute "data-mcz-dl-status" changed to', - el.getAttribute('data-mcz-dl-status'), - ); - if (status === 'active') { - mczMarketoFormAdobeConnectEvent(); - } - }, 300); // 300ms debounce delay - - const observer = new MutationObserver((mutationsList) => { - mutationsList.forEach((mutation) => { - if (mutation.type === 'attributes') { - debouncedCallback(); - } - }); - }); - - observer.observe(el, { - attributes: true, // Observe attribute changes - attributeFilter: ['data-mcz-dl-status'], // Optional: filter specific attributes - }); } diff --git a/events/blocks/marketo-form/marketo-form.js b/events/blocks/marketo-form/marketo-form.js index 6d65ad81..f0061569 100644 --- a/events/blocks/marketo-form/marketo-form.js +++ b/events/blocks/marketo-form/marketo-form.js @@ -3,8 +3,73 @@ import { CheckResourceLocation } from '../../../rs/360-KCI-804/images/mktoTestFo export default async function init(el) { const rows = Array.from(el.children); const resourceLocation = `#${rows[0].textContent.trim().toLowerCase()}`; + const resourceWatch = 'main .section .chrono-box'; el.innerHTML = ''; + + el.setAttribute('data-mcz-dl-status', 'loading'); + await CheckResourceLocation(el, resourceWatch, resourceLocation); -} \ No newline at end of file + + function mczMarketoFormAdobeConnectEvent() { + if (window.mcz_marketoForm_pref?.form?.success?.type === 'adobe_connect') { + const eventUrl = window.mcz_marketoForm_pref?.form?.success?.content; + + // Dispatch custom event for any systems that want to listen + const customEvent = new CustomEvent('marketo-form-completed', { + detail: { + type: 'adobe_connect', + url: eventUrl, + formData: window.mcz_marketoForm_pref?.form || {}, + timestamp: Date.now(), + }, + bubbles: true, + cancelable: false, + }); + + // Dispatch on document for global listening + document.dispatchEvent(customEvent); + + console.log('Marketo form completed - Adobe Connect URL:', eventUrl); + } + } + + // Debounce function to limit rapid calls + function debounce(func, wait) { + let timeout; + return function executedFunction(...args) { + const later = () => { + clearTimeout(timeout); + func(...args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; + } + + // Debounced callback for observer + const debouncedCallback = debounce(() => { + const status = el.getAttribute('data-mcz-dl-status'); + console.log( + 'Attribute "data-mcz-dl-status" changed to', + el.getAttribute('data-mcz-dl-status'), + ); + if (status === 'active') { + mczMarketoFormAdobeConnectEvent(); + } + }, 300); // 300ms debounce delay + + const observer = new MutationObserver((mutationsList) => { + mutationsList.forEach((mutation) => { + if (mutation.type === 'attributes') { + debouncedCallback(); + } + }); + }); + + observer.observe(el, { + attributes: true, // Observe attribute changes + attributeFilter: ['data-mcz-dl-status'], // Optional: filter specific attributes + }); +} diff --git a/events/features/timing-framework/plugins/metadata/plugin.js b/events/features/timing-framework/plugins/metadata/plugin.js index 7b7b5c75..b12b25ba 100644 --- a/events/features/timing-framework/plugins/metadata/plugin.js +++ b/events/features/timing-framework/plugins/metadata/plugin.js @@ -19,6 +19,20 @@ export const metadataStore = { }, }; +// Listen for custom events from other blocks +function setupCustomEventListeners() { + // Listen for marketo-form completion events + document.addEventListener('marketo-form-completed', (event) => { + const { detail } = event; + + // Update metadata store based on event type + if (detail.type === 'adobe_connect' && detail.url) { + metadataStore.set('adobe-connect-url', detail.url); + console.log('Metadata updated from marketo-form-completed event:', detail); + } + }); +} + export default function init(schedule) { const allMetadataInSchedules = schedule.filter((entry) => entry.metadata); allMetadataInSchedules.forEach(({ metadata }) => { @@ -28,5 +42,8 @@ export default function init(schedule) { }); }); + // Set up event listeners for custom events + setupCustomEventListeners(); + return metadataStore; } From e68db8a08f99d694f0391e787ed97d798845a0cf Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Wed, 30 Jul 2025 11:50:18 +0530 Subject: [PATCH 80/93] Review comments incorporated --- events/blocks/anchor-point/anchor-point.js | 7 ++++++ events/blocks/chrono-box/chrono-box.js | 2 -- .../blocks/marketo-form-ui/marketo-form-ui.js | 11 --------- .../mcz-handler.js} | 23 +++++++------------ .../plugins/metadata/plugin.js | 18 +-------------- 5 files changed, 16 insertions(+), 45 deletions(-) create mode 100644 events/blocks/anchor-point/anchor-point.js delete mode 100644 events/blocks/marketo-form-ui/marketo-form-ui.js rename events/blocks/{marketo-form/marketo-form.js => mcz-handler/mcz-handler.js} (79%) diff --git a/events/blocks/anchor-point/anchor-point.js b/events/blocks/anchor-point/anchor-point.js new file mode 100644 index 00000000..6da98c11 --- /dev/null +++ b/events/blocks/anchor-point/anchor-point.js @@ -0,0 +1,7 @@ +export default async function init(el) { + const rows = Array.from(el.children); + const idName = `${rows[0].textContent.trim().toLowerCase()}`; + + el.innerHTML = ''; + el.setAttribute('id', idName); +} diff --git a/events/blocks/chrono-box/chrono-box.js b/events/blocks/chrono-box/chrono-box.js index db56ab19..1658694d 100644 --- a/events/blocks/chrono-box/chrono-box.js +++ b/events/blocks/chrono-box/chrono-box.js @@ -109,8 +109,6 @@ export default async function init(el) { import(`${LIBS}/features/spectrum-web-components/dist/progress-circle.js`), ]); - el.setAttribute('data-mcz-dl-status', 'loading'); - const blockConfig = readBlockConfig(el); const scheduleId = blockConfig?.['schedule-id']; let staticSchedule; diff --git a/events/blocks/marketo-form-ui/marketo-form-ui.js b/events/blocks/marketo-form-ui/marketo-form-ui.js deleted file mode 100644 index a612fee0..00000000 --- a/events/blocks/marketo-form-ui/marketo-form-ui.js +++ /dev/null @@ -1,11 +0,0 @@ -import { LIBS } from '../../scripts/utils.js'; - -const { createTag } = await import(`${LIBS}/utils/utils.js`); - -export default async function init(el) { - const rows = Array.from(el.children); - const idName = `${rows[0].textContent.trim().toLowerCase()}`; - - el.innerHTML = ''; - createTag('div', { id: idName, class: 'marketo-form-ui' }, '', { parent: el }); -} diff --git a/events/blocks/marketo-form/marketo-form.js b/events/blocks/mcz-handler/mcz-handler.js similarity index 79% rename from events/blocks/marketo-form/marketo-form.js rename to events/blocks/mcz-handler/mcz-handler.js index f0061569..8f671cdc 100644 --- a/events/blocks/marketo-form/marketo-form.js +++ b/events/blocks/mcz-handler/mcz-handler.js @@ -1,8 +1,14 @@ import { CheckResourceLocation } from '../../../rs/360-KCI-804/images/mktoTestFormConfig.js'; +import { setMetadata } from '../../../scripts/utils.js'; + +import { metadataStore } from '../../../features/timing-framework/plugins/metadata/plugin.js'; + export default async function init(el) { const rows = Array.from(el.children); const resourceLocation = `#${rows[0].textContent.trim().toLowerCase()}`; + // suggestion to use getElementbyId + const key = rows[1].textContent.trim().toLowerCase(); const resourceWatch = 'main .section .chrono-box'; @@ -15,21 +21,8 @@ export default async function init(el) { function mczMarketoFormAdobeConnectEvent() { if (window.mcz_marketoForm_pref?.form?.success?.type === 'adobe_connect') { const eventUrl = window.mcz_marketoForm_pref?.form?.success?.content; - - // Dispatch custom event for any systems that want to listen - const customEvent = new CustomEvent('marketo-form-completed', { - detail: { - type: 'adobe_connect', - url: eventUrl, - formData: window.mcz_marketoForm_pref?.form || {}, - timestamp: Date.now(), - }, - bubbles: true, - cancelable: false, - }); - - // Dispatch on document for global listening - document.dispatchEvent(customEvent); + setMetadata('adobe-connect-url', eventUrl); + metadataStore.set(key, 'adobe-connect'); console.log('Marketo form completed - Adobe Connect URL:', eventUrl); } diff --git a/events/features/timing-framework/plugins/metadata/plugin.js b/events/features/timing-framework/plugins/metadata/plugin.js index b12b25ba..d4f0411f 100644 --- a/events/features/timing-framework/plugins/metadata/plugin.js +++ b/events/features/timing-framework/plugins/metadata/plugin.js @@ -1,4 +1,4 @@ -import { parseMetadataPath, getCurrentTabId } from '../../../../scripts/utils.js'; +import { parseMetadataPath, getCurrentTabId, setMetadata } from '../../../../scripts/utils.js'; const store = new Map(); const channel = new BroadcastChannel('metadata-store'); @@ -19,19 +19,6 @@ export const metadataStore = { }, }; -// Listen for custom events from other blocks -function setupCustomEventListeners() { - // Listen for marketo-form completion events - document.addEventListener('marketo-form-completed', (event) => { - const { detail } = event; - - // Update metadata store based on event type - if (detail.type === 'adobe_connect' && detail.url) { - metadataStore.set('adobe-connect-url', detail.url); - console.log('Metadata updated from marketo-form-completed event:', detail); - } - }); -} export default function init(schedule) { const allMetadataInSchedules = schedule.filter((entry) => entry.metadata); @@ -42,8 +29,5 @@ export default function init(schedule) { }); }); - // Set up event listeners for custom events - setupCustomEventListeners(); - return metadataStore; } From 9fdc7896dc3d59894d51e81f90f07bfbc9fba4ed Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Wed, 30 Jul 2025 12:03:20 +0530 Subject: [PATCH 81/93] mcz-handler fix --- events/blocks/mcz-handler/mcz-handler.js | 4 ++-- events/features/timing-framework/plugins/metadata/plugin.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/events/blocks/mcz-handler/mcz-handler.js b/events/blocks/mcz-handler/mcz-handler.js index 8f671cdc..a8771a6c 100644 --- a/events/blocks/mcz-handler/mcz-handler.js +++ b/events/blocks/mcz-handler/mcz-handler.js @@ -1,8 +1,8 @@ import { CheckResourceLocation } from '../../../rs/360-KCI-804/images/mktoTestFormConfig.js'; -import { setMetadata } from '../../../scripts/utils.js'; +import { setMetadata } from '../../scripts/utils.js'; -import { metadataStore } from '../../../features/timing-framework/plugins/metadata/plugin.js'; +import { metadataStore } from '../../features/timing-framework/plugins/metadata/plugin.js'; export default async function init(el) { const rows = Array.from(el.children); diff --git a/events/features/timing-framework/plugins/metadata/plugin.js b/events/features/timing-framework/plugins/metadata/plugin.js index d4f0411f..c1004510 100644 --- a/events/features/timing-framework/plugins/metadata/plugin.js +++ b/events/features/timing-framework/plugins/metadata/plugin.js @@ -1,4 +1,4 @@ -import { parseMetadataPath, getCurrentTabId, setMetadata } from '../../../../scripts/utils.js'; +import { parseMetadataPath, getCurrentTabId } from '../../../../scripts/utils.js'; const store = new Map(); const channel = new BroadcastChannel('metadata-store'); From c71e808437caffcac260dde32babc4ca6b6d6085 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Wed, 30 Jul 2025 12:09:39 +0530 Subject: [PATCH 82/93] adding missing css --- events/blocks/anchor-point/anchor-point.css | 0 events/blocks/mcz-handler/mcz-handler.css | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 events/blocks/anchor-point/anchor-point.css create mode 100644 events/blocks/mcz-handler/mcz-handler.css diff --git a/events/blocks/anchor-point/anchor-point.css b/events/blocks/anchor-point/anchor-point.css new file mode 100644 index 00000000..e69de29b diff --git a/events/blocks/mcz-handler/mcz-handler.css b/events/blocks/mcz-handler/mcz-handler.css new file mode 100644 index 00000000..e69de29b From f106a26e6982afb3719b8203104fe57172535afa Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Wed, 30 Jul 2025 12:17:58 +0530 Subject: [PATCH 83/93] minor adobe connect fix --- events/blocks/adobe-connect/adobe-connect.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/events/blocks/adobe-connect/adobe-connect.js b/events/blocks/adobe-connect/adobe-connect.js index 623f2ddf..731177dc 100644 --- a/events/blocks/adobe-connect/adobe-connect.js +++ b/events/blocks/adobe-connect/adobe-connect.js @@ -142,9 +142,4 @@ export default async function init(el) { class: 'fullwidth', style: 'position: relative; z-index: 1;', }, '', { parent: el }); - - // Remove overlay after 7 seconds - setTimeout(() => { - overlay.remove(); - }, 7000); } From b5c3dbf796f92bafa31932e5f0a81abefc0e62f0 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Wed, 30 Jul 2025 12:45:36 +0530 Subject: [PATCH 84/93] revert unwanted changes --- events/blocks/event-agenda/event-agenda.css | 38 +++------------------ head.html | 1 - 2 files changed, 4 insertions(+), 35 deletions(-) diff --git a/events/blocks/event-agenda/event-agenda.css b/events/blocks/event-agenda/event-agenda.css index df617c42..a19ba43f 100644 --- a/events/blocks/event-agenda/event-agenda.css +++ b/events/blocks/event-agenda/event-agenda.css @@ -1,7 +1,8 @@ .event-agenda { + max-width: 1750px; margin: auto; box-sizing: content-box; - padding: 0px; + padding: 32px 20px 0; } .event-agenda h2 { @@ -14,14 +15,12 @@ width: 100%; box-sizing: border-box; } - .event-agenda .agenda-container { margin: 0 auto; display: flex; justify-content: center; max-width: 900px; } - .event-agenda.blade .agenda-container { background-color: var(--color-gray-100); display: flex; @@ -29,21 +28,17 @@ border-radius: 18px; overflow: hidden; } - .event-agenda.blade > .agenda-container > div { flex: 1 1 0; } - .event-agenda .agenda-item-wrapper { padding: 6px 0; font-size: var(--type-body-l-size); } - .event-agenda .agenda-item-wrapper .agenda-time { font-weight: 700; margin-right: 8px; } - .event-agenda .agenda-item-container { display: flex; flex-direction: column; @@ -51,7 +46,6 @@ gap: 32px; align-self: stretch; } - .event-agenda .agenda-item-container .agenda-list-item { border-radius: 5px; display: flex; @@ -59,7 +53,6 @@ align-items: flex-start; align-self: stretch; } - .event-agenda .agenda-list-item .agenda-title-detail-container::before { content: ""; display: block; @@ -67,20 +60,17 @@ background: #D5D0D0; margin-right: 16px; } - .event-agenda .agenda-item-container .agenda-list-item .agenda-title-detail-container { display: flex; align-items: stretch; flex: 1 0 0; } - .event-agenda .agenda-item-container .agenda-list-item .agenda-title-detail { display: flex; align-items: flex-start; flex-direction: column; gap: 2px; } - .event-agenda .agenda-item-container .agenda-list-item .agenda-time { width: 75px; font-weight: 700; @@ -89,14 +79,12 @@ font-style: normal; line-height: 150%; /* 27px */ } - .event-agenda .agenda-list-item .agenda-details { font-size: 16px; font-style: normal; font-weight: 400; line-height: 150%; } - .event-agenda .agenda-list-item .agenda-title { font-size: 20px; font-style: normal; @@ -104,24 +92,20 @@ line-height: 150%; display: contents; } - .event-agenda .venue-img-col { min-width: calc(100vw - 20px); display: flex; justify-content: center; height: 270px; } - .event-agenda .venue-img-col picture { width: 100%; } - .event-agenda .venue-img-col img { width: 100%; height: 100%; object-fit: cover; } - .event-agenda .agenda-items { padding: 40px 20px; display: flex; @@ -131,7 +115,6 @@ width: 100%; box-sizing: border-box; } - .event-agenda .agenda-container .agenda-item-container .column { display: flex; flex-direction: column; @@ -139,57 +122,44 @@ flex: 100%; } -.event-agenda .fullwidth { - width: 100%; - height: 900px; -} - @media (min-width: 900px) { .event-agenda { - padding: 0px; + padding: 40px 20px 32px; } - .event-agenda.blade h2 { + .event-agenda.blade h2 { text-align: left; } - .event-agenda.blade .agenda-container { flex-direction: row; justify-content: center; align-items: center; max-width: 100%; } - .event-agenda .venue-img-col { min-width: 50%; height: 400px; } - .event-agenda .agenda-items-with-image { padding: 40px 56px 40px calc((100% - var(--grid-container-width) - 80px) / 2); } } - @media (min-width: 1440px) { .event-agenda .agenda-items-with-image { padding-left: calc((100% - var(--grid-container-width)) / 2) } - .event-agenda .venue-img-col { height: 560px; } - .event-agenda .agenda-container.more-than-six { max-width: 1200px; } - .event-agenda .agenda-container.more-than-six .agenda-item-container { display: flex; flex-direction: row; column-gap: 40px; width: 100%; } - .event-agenda .agenda-container.more-than-six .agenda-item-container .column { flex: 50%; } diff --git a/head.html b/head.html index 31060e00..373ade09 100644 --- a/head.html +++ b/head.html @@ -2,7 +2,6 @@ - From 1e9216ecb107bedc69cbd516d4d544db22e863be Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Wed, 30 Jul 2025 12:51:54 +0530 Subject: [PATCH 85/93] Lint fixes --- events/blocks/event-agenda/event-agenda.css | 27 ++++++++++++++++++- events/blocks/event-agenda/event-agenda.js | 15 +---------- .../plugins/metadata/plugin.js | 1 - 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/events/blocks/event-agenda/event-agenda.css b/events/blocks/event-agenda/event-agenda.css index a19ba43f..e45baadb 100644 --- a/events/blocks/event-agenda/event-agenda.css +++ b/events/blocks/event-agenda/event-agenda.css @@ -15,12 +15,14 @@ width: 100%; box-sizing: border-box; } + .event-agenda .agenda-container { margin: 0 auto; display: flex; justify-content: center; max-width: 900px; } + .event-agenda.blade .agenda-container { background-color: var(--color-gray-100); display: flex; @@ -28,17 +30,21 @@ border-radius: 18px; overflow: hidden; } + .event-agenda.blade > .agenda-container > div { flex: 1 1 0; } + .event-agenda .agenda-item-wrapper { padding: 6px 0; font-size: var(--type-body-l-size); } + .event-agenda .agenda-item-wrapper .agenda-time { font-weight: 700; margin-right: 8px; } + .event-agenda .agenda-item-container { display: flex; flex-direction: column; @@ -46,6 +52,7 @@ gap: 32px; align-self: stretch; } + .event-agenda .agenda-item-container .agenda-list-item { border-radius: 5px; display: flex; @@ -53,6 +60,7 @@ align-items: flex-start; align-self: stretch; } + .event-agenda .agenda-list-item .agenda-title-detail-container::before { content: ""; display: block; @@ -60,17 +68,20 @@ background: #D5D0D0; margin-right: 16px; } + .event-agenda .agenda-item-container .agenda-list-item .agenda-title-detail-container { display: flex; align-items: stretch; flex: 1 0 0; } + .event-agenda .agenda-item-container .agenda-list-item .agenda-title-detail { display: flex; align-items: flex-start; flex-direction: column; gap: 2px; } + .event-agenda .agenda-item-container .agenda-list-item .agenda-time { width: 75px; font-weight: 700; @@ -79,12 +90,14 @@ font-style: normal; line-height: 150%; /* 27px */ } + .event-agenda .agenda-list-item .agenda-details { font-size: 16px; font-style: normal; font-weight: 400; line-height: 150%; } + .event-agenda .agenda-list-item .agenda-title { font-size: 20px; font-style: normal; @@ -92,20 +105,24 @@ line-height: 150%; display: contents; } + .event-agenda .venue-img-col { min-width: calc(100vw - 20px); display: flex; justify-content: center; height: 270px; } + .event-agenda .venue-img-col picture { width: 100%; } + .event-agenda .venue-img-col img { width: 100%; height: 100%; object-fit: cover; } + .event-agenda .agenda-items { padding: 40px 20px; display: flex; @@ -115,6 +132,7 @@ width: 100%; box-sizing: border-box; } + .event-agenda .agenda-container .agenda-item-container .column { display: flex; flex-direction: column; @@ -127,19 +145,22 @@ padding: 40px 20px 32px; } - .event-agenda.blade h2 { + .event-agenda.blade h2 { text-align: left; } + .event-agenda.blade .agenda-container { flex-direction: row; justify-content: center; align-items: center; max-width: 100%; } + .event-agenda .venue-img-col { min-width: 50%; height: 400px; } + .event-agenda .agenda-items-with-image { padding: 40px 56px 40px calc((100% - var(--grid-container-width) - 80px) / 2); } @@ -148,18 +169,22 @@ .event-agenda .agenda-items-with-image { padding-left: calc((100% - var(--grid-container-width)) / 2) } + .event-agenda .venue-img-col { height: 560px; } + .event-agenda .agenda-container.more-than-six { max-width: 1200px; } + .event-agenda .agenda-container.more-than-six .agenda-item-container { display: flex; flex-direction: row; column-gap: 40px; width: 100%; } + .event-agenda .agenda-container.more-than-six .agenda-item-container .column { flex: 50%; } diff --git a/events/blocks/event-agenda/event-agenda.js b/events/blocks/event-agenda/event-agenda.js index b5b6899b..3239c351 100644 --- a/events/blocks/event-agenda/event-agenda.js +++ b/events/blocks/event-agenda/event-agenda.js @@ -17,21 +17,12 @@ export function convertToLocaleTimeFormat(time, locale) { return formatter.format(date); } -// const agenda = [ -// { -// description: 'test2', -// title: 'test1', -// startTime: '08:00:00', -// }, -// ]; - export default async function init(el) { if (getMetadata('show-agenda-post-event') !== 'true' && document.body.classList.contains('timing-post-event')) { el.remove(); return; } - // createTag('iframe', { src: 'https://livekitqe.dev.adobeconnect.com/event-demo?guestname=Participant', frameborder: '0', allowfullscreen: 'true', class: 'fullwidth' }, '', { parent: el }); const container = createTag('div', { class: 'agenda-container' }, '', { parent: el }); const agendaItemsCol = createTag('div', { class: 'agenda-items' }, '', { parent: container }); @@ -53,7 +44,6 @@ export default async function init(el) { try { agendaArray = JSON.parse(agendaMeta); - // agendaArray = agenda; } catch (error) { window.lana?.log(`Failed to parse agenda metadata:\n${JSON.stringify(error, null, 2)}`); el.remove(); @@ -61,10 +51,7 @@ export default async function init(el) { } if (agendaArray.length <= 0) { - const h2 = el.querySelector('h2'); - h2.remove(); - agendaItemsCol.remove(); - // el.remove(); + el.remove(); return; } diff --git a/events/features/timing-framework/plugins/metadata/plugin.js b/events/features/timing-framework/plugins/metadata/plugin.js index c1004510..7b7b5c75 100644 --- a/events/features/timing-framework/plugins/metadata/plugin.js +++ b/events/features/timing-framework/plugins/metadata/plugin.js @@ -19,7 +19,6 @@ export const metadataStore = { }, }; - export default function init(schedule) { const allMetadataInSchedules = schedule.filter((entry) => entry.metadata); allMetadataInSchedules.forEach(({ metadata }) => { From ca1b17339f79e711ae36206e9bfc9135a069c413 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Wed, 30 Jul 2025 12:52:34 +0530 Subject: [PATCH 86/93] lint fix --- events/blocks/event-agenda/event-agenda.css | 1 + 1 file changed, 1 insertion(+) diff --git a/events/blocks/event-agenda/event-agenda.css b/events/blocks/event-agenda/event-agenda.css index e45baadb..f890ec3e 100644 --- a/events/blocks/event-agenda/event-agenda.css +++ b/events/blocks/event-agenda/event-agenda.css @@ -165,6 +165,7 @@ padding: 40px 56px 40px calc((100% - var(--grid-container-width) - 80px) / 2); } } + @media (min-width: 1440px) { .event-agenda .agenda-items-with-image { padding-left: calc((100% - var(--grid-container-width)) / 2) From f1410a02a3d1a3b22d387b49e55cdc931c8c4a4a Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Wed, 30 Jul 2025 12:58:51 +0530 Subject: [PATCH 87/93] minor class style in .css --- events/blocks/adobe-connect/adobe-connect.css | 266 +++++++++--------- 1 file changed, 128 insertions(+), 138 deletions(-) diff --git a/events/blocks/adobe-connect/adobe-connect.css b/events/blocks/adobe-connect/adobe-connect.css index d3fd283d..73b469d4 100644 --- a/events/blocks/adobe-connect/adobe-connect.css +++ b/events/blocks/adobe-connect/adobe-connect.css @@ -2,156 +2,146 @@ width: 100%; padding: 0; margin: 0; +} - .fullwidth { - width: 100%; - height: 900px; - } - - button { - font-size: var(--type-body-s-size); - background-color: var(--link-color); - min-width: 114px; - height: 40px; - line-height: 20px; - padding: 9px 16px; - border: 0; - border-radius: 24px; - color: #fff; - font-weight: 700; - box-shadow: none; - margin: 0 auto; - cursor: pointer; - transition: background-color 0.13s, color 0.13s; - } - - .hidden { - visibility: hidden !important; - opacity: 0 !important; - } - - /* Overlay background */ - .iframe-overlay { - position: fixed; - inset: 0; - background: rgba(0, 0, 0, 85%); - color: #fff; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - z-index: 9999; - font-family: inherit; - pointer-events: auto; - padding: 10px; - gap: 16px; - flex-shrink: 0; - margin: 0; +.adobe-connect .fullwidth { + width: 100%; + height: 900px; +} - /* Close button */ - .overlay-close-btn { - display: flex; - width: 22px; - height: 22px; - align-items: flex-start; - position: absolute; - right: 32px; - top: 33px; - } +.adobe-connect button { + font-size: var(--type-body-s-size); + background-color: var(--link-color); + min-width: 114px; + height: 40px; + line-height: 20px; + padding: 9px 16px; + border: 0; + border-radius: 24px; + color: #fff; + font-weight: 700; + box-shadow: none; + margin: 0 auto; + cursor: pointer; + transition: background-color 0.13s, color 0.13s; +} - /* Heading */ - .overlay-heading, - .overlay-heading-yrs { - font-weight: 700; - text-align: center; - line-height: 125%; - font-style: normal; - color: #fff; - font-size: 24px; - align-self: stretch; - margin: 0; - } +.adobe-connect .hidden { + visibility: hidden !important; + opacity: 0 !important; +} - /* Subheading */ - .overlay-subheading { - width: 245px; - color: #FFF; - text-align: center; - font-size: 16px; - font-weight: 700; - line-height: 125%; - } +/* Overlay background */ +.adobe-connect .iframe-overlay { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 85%); + color: #fff; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + z-index: 9999; + font-family: inherit; + pointer-events: auto; + padding: 10px; + gap: 16px; + flex-shrink: 0; + margin: 0; +} - /* Illustration */ - .overlay-illustration { - margin: 40px 0 40px 0; - display: flex; - justify-content: center; - } +.adobe-connect .iframe-overlay .overlay-close-btn { + display: flex; + width: 22px; + height: 22px; + align-items: flex-start; + position: absolute; + right: 32px; + top: 33px; +} - /* Best viewed in landscape */ - .overlay-landscape { - height: 22px; - align-self: stretch; - color: #FFF; - text-align: center; - font-size: 18px; - font-style: normal; - font-weight: 700; - line-height: 125%; - /* 22.5px */ - } +.adobe-connect .iframe-overlay .overlay-heading, +.adobe-connect .iframe-overlay .overlay-heading-yrs { + font-weight: 700; + text-align: center; + line-height: 125%; + font-style: normal; + color: #fff; + font-size: 24px; + align-self: stretch; + margin: 0; +} - /* Rotate your phone message */ - .overlay-rotate-msg { - align-self: stretch; - color: #FFF; - text-align: center; - font-size: 12px; - font-style: normal; - font-weight: 400; - line-height: 150%; - /* 18px */ - } +.adobe-connect .iframe-overlay .overlay-subheading { + width: 245px; + color: #FFF; + text-align: center; + font-size: 16px; + font-weight: 700; + line-height: 125%; +} - /* Continue to webinar button */ - .overlay-continue-btn { - height: 50px; - background: #3B63FB; - color: #FFF; - text-align: center; - font-size: 19px; - font-style: normal; - font-weight: 700; - padding: 12px 24px 14px 24px; - border-radius: 100px; - line-height: 24px; - /* 126.316% */ - margin-top: 40px; - } +.adobe-connect .iframe-overlay .overlay-illustration { + margin: 40px 0 40px 0; + display: flex; + justify-content: center; +} - @media only screen and (orientation: portrait) { - .overlay-heading-yrs { - display: none; - } - } +.adobe-connect .iframe-overlay .overlay-landscape { + height: 22px; + align-self: stretch; + color: #FFF; + text-align: center; + font-size: 18px; + font-style: normal; + font-weight: 700; + line-height: 125%; + /* 22.5px */ +} - @media only screen and (orientation: landscape) { - .overlay-heading { - display: none; - } +.adobe-connect .iframe-overlay .overlay-rotate-msg { + align-self: stretch; + color: #FFF; + text-align: center; + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 150%; + /* 18px */ +} - .overlay-subheading { - display: none; - } +.adobe-connect .iframe-overlay .overlay-continue-btn { + height: 50px; + background: #3B63FB; + color: #FFF; + text-align: center; + font-size: 19px; + font-style: normal; + font-weight: 700; + padding: 12px 24px 14px 24px; + border-radius: 100px; + line-height: 24px; + /* 126.316% */ + margin-top: 40px; +} - .overlay-landscape { - display: none; - } +@media only screen and (orientation: portrait) { + .adobe-connect .iframe-overlay .overlay-heading-yrs { + display: none; + } +} - .overlay-rotate-msg { - display: none; - } - } +@media only screen and (orientation: landscape) { + .adobe-connect .iframe-overlay .overlay-heading { + display: none; + } + .adobe-connect .iframe-overlay .overlay-subheading { + display: none; + } + .adobe-connect .iframe-overlay .overlay-landscape { + display: none; + } + .adobe-connect .iframe-overlay .overlay-rotate-msg { + display: none; } } From 25fb3d1223900f73602cd1acb55a683ee1beb6d5 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Thu, 31 Jul 2025 16:37:00 +0530 Subject: [PATCH 88/93] Review comments --- events/blocks/adobe-connect/adobe-connect.js | 7 +- events/blocks/mcz-handler/mcz-handler.js | 9 +- rs/360-KCI-804/images/mktoTestFormConfig.js | 558 +++++++++---------- 3 files changed, 284 insertions(+), 290 deletions(-) diff --git a/events/blocks/adobe-connect/adobe-connect.js b/events/blocks/adobe-connect/adobe-connect.js index 731177dc..afbeb2f7 100644 --- a/events/blocks/adobe-connect/adobe-connect.js +++ b/events/blocks/adobe-connect/adobe-connect.js @@ -2,6 +2,7 @@ import { LIBS, getMetadata } from '../../scripts/utils.js'; const { createTag } = await import(`${LIBS}/utils/utils.js`); + //TODO: remove post validation with marketo integration. function addParams(searchParams, params, key, value) { if (params.has(key)) { searchParams[key] = params.get(key); @@ -10,6 +11,7 @@ function addParams(searchParams, params, key, value) { } } + //TODO: remove post validation with marketo integration. function addSearchParams(url, searchParams) { const urlObj = new URL(url); for (const [key, value] of Object.entries(searchParams)) { @@ -18,6 +20,7 @@ function addSearchParams(url, searchParams) { return urlObj.toString(); } + //TODO: remove post validation with marketo integration. function getSearchParamsFromCurrentUrl() { const params = new URL(window.location.href).searchParams; const searchParams = {}; @@ -117,7 +120,7 @@ export default async function init(el) { overlayElem.classList.add('hidden'); } - const searchParams = getSearchParamsFromCurrentUrl(); + if (getMetadata('adobe-connect-url')) { url = getMetadata('adobe-connect-url'); @@ -126,6 +129,8 @@ export default async function init(el) { return; } + //TODO: remove post validation with marketo integration. + const searchParams = getSearchParamsFromCurrentUrl(); url = addSearchParams(url, searchParams); if (overlayElem && shouldShowOverlay()) { diff --git a/events/blocks/mcz-handler/mcz-handler.js b/events/blocks/mcz-handler/mcz-handler.js index a8771a6c..82ab18b0 100644 --- a/events/blocks/mcz-handler/mcz-handler.js +++ b/events/blocks/mcz-handler/mcz-handler.js @@ -1,9 +1,6 @@ import { CheckResourceLocation } from '../../../rs/360-KCI-804/images/mktoTestFormConfig.js'; - import { setMetadata } from '../../scripts/utils.js'; -import { metadataStore } from '../../features/timing-framework/plugins/metadata/plugin.js'; - export default async function init(el) { const rows = Array.from(el.children); const resourceLocation = `#${rows[0].textContent.trim().toLowerCase()}`; @@ -18,8 +15,10 @@ export default async function init(el) { await CheckResourceLocation(el, resourceWatch, resourceLocation); - function mczMarketoFormAdobeConnectEvent() { + async function mczMarketoFormAdobeConnectEvent() { if (window.mcz_marketoForm_pref?.form?.success?.type === 'adobe_connect') { + const { metadataStore } = await import('../../features/timing-framework/plugins/metadata/plugin.js'); + const eventUrl = window.mcz_marketoForm_pref?.form?.success?.content; setMetadata('adobe-connect-url', eventUrl); metadataStore.set(key, 'adobe-connect'); @@ -44,6 +43,8 @@ export default async function init(el) { // Debounced callback for observer const debouncedCallback = debounce(() => { const status = el.getAttribute('data-mcz-dl-status'); + + // TODO: remove this console.log post validation with marketo integration. console.log( 'Attribute "data-mcz-dl-status" changed to', el.getAttribute('data-mcz-dl-status'), diff --git a/rs/360-KCI-804/images/mktoTestFormConfig.js b/rs/360-KCI-804/images/mktoTestFormConfig.js index 413da89c..8580eb7a 100644 --- a/rs/360-KCI-804/images/mktoTestFormConfig.js +++ b/rs/360-KCI-804/images/mktoTestFormConfig.js @@ -3,14 +3,14 @@ // ## if ( - typeof mczFrm_mkto_testing_loader != "function" && - typeof mczFrm_mkto_testing_loader == "undefined" + typeof mczFrm_mkto_testing_loader !== 'function' + && typeof mczFrm_mkto_testing_loader === 'undefined' ) { //* //* async function getMktToken() { - const storageKey = "mkt_tok"; - let mktToken = ""; + const storageKey = 'mkt_tok'; + let mktToken = ''; if (window.__mktTokVal && window.__mktTokVal?.trim()?.length > 0) { return window.__mktTokVal; @@ -26,7 +26,7 @@ if ( console.warn(`Could not save ${storageKey} to storage`, e); } } else { - mktToken = sessionStorage.getItem(storageKey) || localStorage.getItem(storageKey) || ""; + mktToken = sessionStorage.getItem(storageKey) || localStorage.getItem(storageKey) || ''; } window.__mktTokVal = mktToken; @@ -45,23 +45,23 @@ if ( //* //* - //hide Join button + // hide Join button - var BASE_URL = "https://engage.marketo.com"; - var MUNCHKIN_ID = "360-KCI-804"; + const BASE_URL = 'https://engage.marketo.com'; + const MUNCHKIN_ID = '360-KCI-804'; var mczFrm_mkto_testing_loader = (el, resourceLocation) => { - let cssFast = ` + const cssFast = ` button[daa-ll="Join the event-1--"] { visibility: hidden !important; opacity: 0 !important; } `; - let cssLinkFast = document.createElement("style"); + const cssLinkFast = document.createElement('style'); cssLinkFast.innerHTML = cssFast; document.head.appendChild(cssLinkFast); - let formID = 3131; - let resourceFormHTML = ` + const formID = 3131; + const resourceFormHTML = `
@@ -71,11 +71,10 @@ if (
`; - const marketoCSSresource = "https://business.adobe.com/libs/blocks/marketo/marketo.css"; + const marketoCSSresource = 'https://business.adobe.com/libs/blocks/marketo/marketo.css'; - let marketoConfiguratorLink = - "eyJmb3JtLnRlbXBsYXRlIjoicmVxdWVzdF9mb3JfaW5mb3JtYXRpb24iLCJmb3JtLnN1YnR5cGUiOiJyZXF1ZXN0X2Zvcl9pbmZvcm1hdGlvbiIsInByb2dyYW0uY2FtcGFpZ25pZHMuc2ZkYyI6IjcwMTE0MDAwMDAyWFl2SUFBVyIsInByb2dyYW0ucG9pIjoiTUFSS0VUT0VOR0FHRU1FTlRQTEFURk9STSIsImZvcm0uc3VjY2Vzcy5jb250ZW50IjoiaHR0cHM6Ly9idXNpbmVzcy5hZG9iZS5jb20vcmVzb3VyY2VzL2Vib29rcy9wcm92aW5nLXRoZS1pbXBhY3Qtb2YtbWFya2V0aW5nLW9uLXJldmVudWUvdGhhbmsteW91Lmh0bWwiLCJmb3JtLnN1Y2Nlc3MudHlwZSI6IiIsInByb2dyYW0uY29udGVudC50eXBlIjoiIiwicHJvZ3JhbS5jb250ZW50LmlkIjoiIiwiZmllbGRfdmlzaWJpbGl0eS5uYW1lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBob25lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnkiOiJyZXF1aXJlZCIsImZpZWxkX3Zpc2liaWxpdHkud2Vic2l0ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5mdW5jdGlvbmFsX2FyZWEiOiJGdW5jdGlvbmFsIEFyZWEtRFgiLCJmaWVsZF92aXNpYmlsaXR5LnN0YXRlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBvc3Rjb2RlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnlfc2l6ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5wcm9kdWN0cyI6ImhpZGRlbiIsImZpZWxkX2ZpbHRlcnMuaW5kdXN0cnkiOiJoaWRkZW4iLCJmaWVsZF9maWx0ZXJzLmpvYl9yb2xlIjoiYWxsIiwiZmllbGRfdmlzaWJpbGl0eS5jb21tZW50cyI6ImhpZGRlbiIsImZpZWxkX3Zpc2liaWxpdHkuZGVtbyI6ImhpZGRlbiIsInByb2dyYW0uY29wYXJ0bmVybmFtZXMiOiIiLCJwcm9ncmFtLmNhbXBhaWduaWRzLmV4dGVybmFsIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5yZXRvdWNoIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5vbnNpdGUiOiIiLCJwcm9ncmFtLmFkZGl0aW9uYWxfZm9ybV9pZCI6IiIsImZvcm0gaWQiOiIxNzIzIiwibWFya2V0byBtdW5ja2luIjoiMzYwLUtDSS04MDQiLCJtYXJrZXRvIGhvc3QiOiJlbmdhZ2UuYWRvYmUuY29tIiwiZm9ybSB0eXBlIjoibWFya2V0b19mb3JtIn0"; - let marketoConfiguratorHTML = ` + const marketoConfiguratorLink = 'eyJmb3JtLnRlbXBsYXRlIjoicmVxdWVzdF9mb3JfaW5mb3JtYXRpb24iLCJmb3JtLnN1YnR5cGUiOiJyZXF1ZXN0X2Zvcl9pbmZvcm1hdGlvbiIsInByb2dyYW0uY2FtcGFpZ25pZHMuc2ZkYyI6IjcwMTE0MDAwMDAyWFl2SUFBVyIsInByb2dyYW0ucG9pIjoiTUFSS0VUT0VOR0FHRU1FTlRQTEFURk9STSIsImZvcm0uc3VjY2Vzcy5jb250ZW50IjoiaHR0cHM6Ly9idXNpbmVzcy5hZG9iZS5jb20vcmVzb3VyY2VzL2Vib29rcy9wcm92aW5nLXRoZS1pbXBhY3Qtb2YtbWFya2V0aW5nLW9uLXJldmVudWUvdGhhbmsteW91Lmh0bWwiLCJmb3JtLnN1Y2Nlc3MudHlwZSI6IiIsInByb2dyYW0uY29udGVudC50eXBlIjoiIiwicHJvZ3JhbS5jb250ZW50LmlkIjoiIiwiZmllbGRfdmlzaWJpbGl0eS5uYW1lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBob25lIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnkiOiJyZXF1aXJlZCIsImZpZWxkX3Zpc2liaWxpdHkud2Vic2l0ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5mdW5jdGlvbmFsX2FyZWEiOiJGdW5jdGlvbmFsIEFyZWEtRFgiLCJmaWVsZF92aXNpYmlsaXR5LnN0YXRlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LnBvc3Rjb2RlIjoicmVxdWlyZWQiLCJmaWVsZF92aXNpYmlsaXR5LmNvbXBhbnlfc2l6ZSI6InJlcXVpcmVkIiwiZmllbGRfZmlsdGVycy5wcm9kdWN0cyI6ImhpZGRlbiIsImZpZWxkX2ZpbHRlcnMuaW5kdXN0cnkiOiJoaWRkZW4iLCJmaWVsZF9maWx0ZXJzLmpvYl9yb2xlIjoiYWxsIiwiZmllbGRfdmlzaWJpbGl0eS5jb21tZW50cyI6ImhpZGRlbiIsImZpZWxkX3Zpc2liaWxpdHkuZGVtbyI6ImhpZGRlbiIsInByb2dyYW0uY29wYXJ0bmVybmFtZXMiOiIiLCJwcm9ncmFtLmNhbXBhaWduaWRzLmV4dGVybmFsIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5yZXRvdWNoIjoiIiwicHJvZ3JhbS5jYW1wYWlnbmlkcy5vbnNpdGUiOiIiLCJwcm9ncmFtLmFkZGl0aW9uYWxfZm9ybV9pZCI6IiIsImZvcm0gaWQiOiIxNzIzIiwibWFya2V0byBtdW5ja2luIjoiMzYwLUtDSS04MDQiLCJtYXJrZXRvIGhvc3QiOiJlbmdhZ2UuYWRvYmUuY29tIiwiZm9ybSB0eXBlIjoibWFya2V0b19mb3JtIn0'; + const marketoConfiguratorHTML = `
@@ -86,58 +85,58 @@ if (
`; - const cssLink = document.createElement("link"); - cssLink.rel = "stylesheet"; + const cssLink = document.createElement('link'); + cssLink.rel = 'stylesheet'; cssLink.href = marketoCSSresource; document.head.appendChild(cssLink); let marketoConfiguratorJSON = {}; try { marketoConfiguratorJSON = JSON.parse( - decodeURIComponent(escape(window.atob(marketoConfiguratorLink))) + decodeURIComponent(escape(window.atob(marketoConfiguratorLink))), ); } catch (e) { - console.error("Error parsing Marketo Configurator JSON", e); + console.error('Error parsing Marketo Configurator JSON', e); } - let use_marketoConfiguratorLink = false; + const use_marketoConfiguratorLink = false; - let mcz_marketoForm_pref_local = { + const mcz_marketoForm_pref_local = { sync_profiles: {}, - "marketo munckin": "360-KCI-804", - "marketo host": "engage.adobe.com", - "form id": "3131", + 'marketo munckin': '360-KCI-804', + 'marketo host': 'engage.adobe.com', + 'form id': '3131', form: { - template: "flex_event", + template: 'flex_event', success: { - type: "adobe_connect", - content: "https://livekitqe.dev.adobeconnect.com/paxlkm0gwsj4", + type: 'adobe_connect', + content: 'https://livekitqe.dev.adobeconnect.com/paxlkm0gwsj4', delay: 5000, confirm: false, }, - baseSite: "https://business.adobe.com", + baseSite: 'https://business.adobe.com', id: 3131, }, program: { campaignids: { - sfdc: "7015Y000004BWOnQAO", - external: "", - retouch: "", - onsite: "", - cgen: "", - cuid: "", + sfdc: '7015Y000004BWOnQAO', + external: '', + retouch: '', + onsite: '', + cgen: '', + cuid: '', }, - poi: "MARKETOENGAGEMENTPLATFORM", - additional_form_id: "", - copartnernames: "", + poi: 'MARKETOENGAGEMENTPLATFORM', + additional_form_id: '', + copartnernames: '', marketo_asset: { - name: "", - id: "", + name: '', + id: '', }, event: { - type: "adobe_connect", //connect_recording or video - subtype: "flex_event", - id: "mcz114328", + type: 'adobe_connect', // connect_recording or video + subtype: 'flex_event', + id: 'mcz114328', status: { viewport: { width: 1024, @@ -146,15 +145,15 @@ if ( audio: true, }, activity: { - start: "2025-06-07-10:00", - end: "2025-06-07-10:00", + start: '2025-06-07-10:00', + end: '2025-06-07-10:00', duration_ticks: 1000, active_ticks: 1000, log: [ { - type: "adobe_connect", - subtype: "flex_event", - id: "ACTEST4242", + type: 'adobe_connect', + subtype: 'flex_event', + id: 'ACTEST4242', }, ], }, @@ -162,39 +161,39 @@ if ( }, }, status: { - label: "invited", - milestone: "responded", - is: "1001", - dateTime: "2025-06-07-10:00", + label: 'invited', + milestone: 'responded', + is: '1001', + dateTime: '2025-06-07-10:00', }, status_previous: { - label: "invited", - milestone: "responded", - is: "1001", - dateTime: "2025-06-07-10:00", + label: 'invited', + milestone: 'responded', + is: '1001', + dateTime: '2025-06-07-10:00', }, }, field_visibility: { - name: "required", - phone: "hidden", - company: "visible", - website: "hidden", - state: "hidden", - postcode: "hidden", + name: 'required', + phone: 'hidden', + company: 'visible', + website: 'hidden', + state: 'hidden', + postcode: 'hidden', }, field_filters: { - functional_area: "Functional Area-DX", - products: "hidden", - industry: "hidden", - job_role: "hidden", - comments: "hidden", - demo: "hidden", + functional_area: 'Functional Area-DX', + products: 'hidden', + industry: 'hidden', + job_role: 'hidden', + comments: 'hidden', + demo: 'hidden', }, }; if (use_marketoConfiguratorLink) { - for (let key in marketoConfiguratorJSON) { - let keyArray = key.split("."); + for (const key in marketoConfiguratorJSON) { + const keyArray = key.split('.'); let obj = mcz_marketoForm_pref_local; for (let i = 0; i < keyArray.length - 1; i++) { if (!obj[keyArray[i]]) { @@ -206,59 +205,58 @@ if ( } } - if (!window.location.search.includes("preview=1")) { - history.pushState({}, "", `${window.location.pathname}?preview=1`); + if (!window.location.search.includes('preview=1')) { + history.pushState({}, '', `${window.location.pathname}?preview=1`); } window.mcz_marketoForm_pref = JSON.parse(JSON.stringify(mcz_marketoForm_pref_local)); - var loadScript = (url, type, { mode } = {}) => - new Promise((resolve, reject) => { - let script = document.querySelector(`head > script[src="${url}"]`); - if (!script) { - const { head } = document; - script = document.createElement("script"); - script.setAttribute("src", url); - if (type) { - script.setAttribute("type", type); - } - if (["async", "defer"].includes(mode)) script.setAttribute(mode, true); - head.append(script); + const loadScript = (url, type, { mode } = {}) => new Promise((resolve, reject) => { + let script = document.querySelector(`head > script[src="${url}"]`); + if (!script) { + const { head } = document; + script = document.createElement('script'); + script.setAttribute('src', url); + if (type) { + script.setAttribute('type', type); } + if (['async', 'defer'].includes(mode)) script.setAttribute(mode, true); + head.append(script); + } - if (script.dataset.loaded) { - resolve(script); - return; - } + if (script.dataset.loaded) { + resolve(script); + return; + } - const onScript = (event) => { - script.removeEventListener("load", onScript); - script.removeEventListener("error", onScript); + const onScript = (event) => { + script.removeEventListener('load', onScript); + script.removeEventListener('error', onScript); - if (event.type === "error") { - reject(new Error(`error loading script: ${script.src}`)); - } else if (event.type === "load") { - script.dataset.loaded = true; - resolve(script); - } - }; + if (event.type === 'error') { + reject(new Error(`error loading script: ${script.src}`)); + } else if (event.type === 'load') { + script.dataset.loaded = true; + resolve(script); + } + }; - script.addEventListener("load", onScript); - script.addEventListener("error", onScript); - }); + script.addEventListener('load', onScript); + script.addEventListener('error', onScript); + }); - const resourceForm = document.createElement("div"); + const resourceForm = document.createElement('div'); resourceForm.innerHTML = resourceFormHTML; if (document.querySelector(resourceLocation)) { document.querySelector(resourceLocation).appendChild(resourceForm); } else { - console.log("resourceLocation not found", resourceLocation); + console.log('resourceLocation not found', resourceLocation); } loadScript(`${BASE_URL}/js/forms2/js/forms2.min.js`) .then(() => { const { MktoForms2 } = window; - if (!MktoForms2) throw new Error("Marketo forms not loaded"); + if (!MktoForms2) throw new Error('Marketo forms not loaded'); MktoForms2.loadForm(`${BASE_URL}`, MUNCHKIN_ID, formID); MktoForms2.whenReady((form) => { @@ -266,15 +264,15 @@ if ( }); }) .catch(() => { - console.error("Error loading Marketo form"); + console.error('Error loading Marketo form'); }); window.addMunchkin = async function ( - munchkinId = "360-KCI-804", - pageFromEventId = "", - mktToken = "" + munchkinId = '360-KCI-804', + pageFromEventId = '', + mktToken = '', ) { - loadScript(`https://munchkin.marketo.net/munchkin.js`) + loadScript('https://munchkin.marketo.net/munchkin.js') .then(() => { Munchkin.init(munchkinId, { customName: `Testing BACOM Connect UX ${pageFromEventId}`, @@ -282,37 +280,36 @@ if ( }); }) .catch(() => { - console.error("Error loading Munchkin.js"); + console.error('Error loading Munchkin.js'); }); }; mczFrm_createProgramSyncIframe(); }; - window.mcz_marketoForm_adobe_connect_event = (event_url = "") => { - let final_url = ""; - if (event_url != "") { + window.mcz_marketoForm_adobe_connect_event = (event_url = '') => { + let final_url = ''; + if (event_url != '') { final_url = event_url.trim(); } - let adobe_connect_status = - window.mcz_marketoForm_pref?.program?.event?.adobe_connect?.status || null; + let adobe_connect_status = window.mcz_marketoForm_pref?.program?.event?.adobe_connect?.status || null; if (adobe_connect_status == null) { adobe_connect_status = {}; } - adobe_connect_status.overall = "active"; + adobe_connect_status.overall = 'active'; mczFrm_saveSnapshot(); - if (document.querySelector(".marketo-form-wrapper")) { - document.querySelector(".marketo-form-wrapper").classList.add("hide"); + if (document.querySelector('.marketo-form-wrapper')) { + document.querySelector('.marketo-form-wrapper').classList.add('hide'); } if (document.querySelector('.adobe-connect button[daa-ll*="Join"]')) { document.querySelector('.adobe-connect button[daa-ll*="Join"]').click(); } - console.log("adobe_connect_event", final_url); + console.log('adobe_connect_event', final_url); - // To lookup a resource which has attribute 'data-mcz-dl-status'. + // To lookup a resource which has attribute 'data-mcz-dl-status'. // Required for loading adobe connect player const resource = document.querySelector('[data-mcz-dl-status]'); if (resource) { @@ -348,12 +345,11 @@ if ( let serverTimeOffset = mcz_marketoForm_pref?.program?.marketo_asset?.time?.offset || null; try { if (serverTimeOffset == null) { - let serverTimeRaw = - mcz_marketoForm_pref?.program?.marketo_asset?.time?.systemDateTime || null; + const serverTimeRaw = mcz_marketoForm_pref?.program?.marketo_asset?.time?.systemDateTime || null; if (serverTimeRaw) { - let serverTimeInitial = new Date(serverTimeRaw).getTime(); + const serverTimeInitial = new Date(serverTimeRaw).getTime(); if (!isNaN(serverTimeInitial)) { - let clientTimeInitial = new Date().getTime() + serverTimeOffset; + const clientTimeInitial = new Date().getTime() + serverTimeOffset; serverTimeOffset = serverTimeInitial - clientTimeInitial; mcz_marketoForm_pref.program.marketo_asset.time.offset = serverTimeOffset; } @@ -364,24 +360,24 @@ if ( serverTimeOffset = parseInt(serverTimeOffset) || 0; } } catch (e) { - console.warn("Error getting server time offset", e); + console.warn('Error getting server time offset', e); serverTimeOffset = 0; } - if (typeof serverTimeOffset === "undefined") { + if (typeof serverTimeOffset === 'undefined') { return new Date(); } return new Date(new Date().getTime() + serverTimeOffset); } - var timeUntilInterval = null; + let timeUntilInterval = null; function mczFrm_updateTimeUntil() { - let base = window?.mcz_marketoForm_pref || {}; - let endDateTime = base?.program?.event?.dateTime?.pst?.dateTimeEnd || null; - let startDateTime = base?.program?.event?.dateTime?.pst?.dateTimeStart || null; - let nowDateTime = mczFrm_currentMarketoTime(); - let general_status = "pending"; + const base = window?.mcz_marketoForm_pref || {}; + const endDateTime = base?.program?.event?.dateTime?.pst?.dateTimeEnd || null; + const startDateTime = base?.program?.event?.dateTime?.pst?.dateTimeStart || null; + const nowDateTime = mczFrm_currentMarketoTime(); + let general_status = 'pending'; if (endDateTime == null || startDateTime == null || nowDateTime == null) { - console.warn("No end or now date time found for this event"); + console.warn('No end or now date time found for this event'); return null; } @@ -390,13 +386,13 @@ if ( adobe_connect_status = {}; } - general_status = adobe_connect_status.overall || "register"; + general_status = adobe_connect_status.overall || 'register'; - let endDate = new Date(endDateTime); - let startDate = new Date(startDateTime); - let nowDate = new Date(nowDateTime); - let timeUntilEnds = mczFrm_getTimeUntil(endDate, nowDate); - let timeUntilStart = mczFrm_getTimeUntil(startDate, nowDate); + const endDate = new Date(endDateTime); + const startDate = new Date(startDateTime); + const nowDate = new Date(nowDateTime); + const timeUntilEnds = mczFrm_getTimeUntil(endDate, nowDate); + const timeUntilStart = mczFrm_getTimeUntil(startDate, nowDate); let stillReview = true; @@ -432,15 +428,15 @@ if ( } } - let duration = mczFrm_getTimeUntil(endDate, startDate); + const duration = mczFrm_getTimeUntil(endDate, startDate); base.program.event.dateTime.duration = duration; - let remaining = mczFrm_getTimeUntil(endDate, nowDate); + const remaining = mczFrm_getTimeUntil(endDate, nowDate); base.program.event.dateTime.remaining = remaining; // Calculate halfway point using total milliseconds for accuracy if (duration?.timeUntil > 0 && stillReview) { - let half_duration_ms = duration.timeUntil / 2; + const half_duration_ms = duration.timeUntil / 2; if (remaining?.timeUntil <= half_duration_ms && remaining?.timeUntil > 0) { adobe_connect_status.is_halfway_through = true; } @@ -451,12 +447,12 @@ if ( adobe_connect_status.about_to_end = true; } - //check if finished + // check if finished if ( - adobe_connect_status.has_started && - remaining?.timeUntil > 0 && - remaining.minutes <= 2 && - stillReview + adobe_connect_status.has_started + && remaining?.timeUntil > 0 + && remaining.minutes <= 2 + && stillReview ) { adobe_connect_status.has_ended = true; adobe_connect_status.has_finished = true; @@ -466,15 +462,15 @@ if ( adobe_connect_status.can_attend = false; adobe_connect_status.can_register = false; adobe_connect_status.has_started = true; - general_status = "finished"; + general_status = 'finished'; stillReview = false; } - //open_minutes and close_minutes - let open_minutes = base?.program?.event?.dateTime?.pst?.open_minutes || 10; //you can join 10 minutes before the event starts - let close_minutes = base?.program?.event?.dateTime?.pst?.close_minutes || 999; //you can join 999 minutes after the event starts + // open_minutes and close_minutes + const open_minutes = base?.program?.event?.dateTime?.pst?.open_minutes || 10; // you can join 10 minutes before the event starts + const close_minutes = base?.program?.event?.dateTime?.pst?.close_minutes || 999; // you can join 999 minutes after the event starts - //workout if the event is open or closed + // workout if the event is open or closed let doorsOpen = false; if (timeUntilStart?.minutes > 0 && stillReview) { if (timeUntilStart?.minutes <= open_minutes) { @@ -486,7 +482,7 @@ if ( adobe_connect_status.has_ended = false; adobe_connect_status.is_reg_open = true; adobe_connect_status.is_reg_closed = false; - general_status = "active"; + general_status = 'active'; stillReview = false; } } @@ -499,7 +495,7 @@ if ( adobe_connect_status.has_started = true; adobe_connect_status.is_reg_open = false; adobe_connect_status.is_reg_closed = true; - general_status = "active"; + general_status = 'active'; stillReview = false; } } @@ -512,37 +508,34 @@ if ( base.program.event.status = general_status; base.program.event.id = window?.programId || null; - console.log("timeUntilStart", timeUntilStart); + console.log('timeUntilStart', timeUntilStart); if (timeUntilStart.minutes <= 30) { if (!timeUntilInterval) { timeUntilInterval = setInterval(mczFrm_updateTimeUntil, 1000); } - } else { - if (timeUntilInterval) { - clearInterval(timeUntilInterval); - timeUntilInterval = null; - } + } else if (timeUntilInterval) { + clearInterval(timeUntilInterval); + timeUntilInterval = null; } } - function mczFrm_ACE_confirmURL(url_name = "", url = "") { + function mczFrm_ACE_confirmURL(url_name = '', url = '') { try { - let confirmLocation = - window.mcz_marketoForm_pref?.program?.event?.adobe_connect?.urls?.[url_name] || null; + const confirmLocation = window.mcz_marketoForm_pref?.program?.event?.adobe_connect?.urls?.[url_name] || null; if (confirmLocation == null) { return false; } - let current_status = confirmLocation?.valid_url || false; + const current_status = confirmLocation?.valid_url || false; if (current_status) { return true; } - if (url.trim() == "") { - //get the url from the config and we will validate it. - url = confirmLocation.url || ""; - if (url.trim() == "") { + if (url.trim() == '') { + // get the url from the config and we will validate it. + url = confirmLocation.url || ''; + if (url.trim() == '') { return false; } } @@ -555,7 +548,7 @@ if ( } catch (e) { confirmLocation.valid_url = false; confirmLocation.url_obj = {}; - confirmLocation.url = ""; + confirmLocation.url = ''; return false; } return true; @@ -569,19 +562,19 @@ if ( //* Communication frunctions //* async function mczFrm_createProgramSyncIframe() { - let mktToken = window.getMktToken; - let pageFromEventId = mcz_marketoForm_pref.program.event.id || ""; - if (pageFromEventId == "") { - console.log("No event id found, skipping profile sync iframe."); + const mktToken = window.getMktToken; + const pageFromEventId = mcz_marketoForm_pref.program.event.id || ''; + if (pageFromEventId == '') { + console.log('No event id found, skipping profile sync iframe.'); return; } - let munchkinId = MUNCHKIN_ID || "360-KCI-804"; + const munchkinId = MUNCHKIN_ID || '360-KCI-804'; addMunchkin(munchkinId, pageFromEventId, mktToken); - let programIDOnly = pageFromEventId.replace(/[^0-9]/g, ""); - let programfromStorage = await mczFrm_aquireFromStorage(`pr_${programIDOnly}_`); + const programIDOnly = pageFromEventId.replace(/[^0-9]/g, ''); + const programfromStorage = await mczFrm_aquireFromStorage(`pr_${programIDOnly}_`); if (programfromStorage) { - console.log("MCZ Form, Updating DL from storage:", programfromStorage); + console.log('MCZ Form, Updating DL from storage:', programfromStorage); mczFrm_updateDL(programfromStorage); } @@ -590,13 +583,13 @@ if ( baseURL = `${baseURL}?mkt_tok=${mktToken}`; } - const iframe = document.createElement("iframe"); - iframe.sandbox = "allow-scripts allow-same-origin"; + const iframe = document.createElement('iframe'); + iframe.sandbox = 'allow-scripts allow-same-origin'; iframe.src = baseURL; - iframe.style.display = "none"; - iframe.id = "mcz-marketo-program-iframe"; + iframe.style.display = 'none'; + iframe.id = 'mcz-marketo-program-iframe'; document.body.appendChild(iframe); - console.log("Profile sync iframe added with URL:", iframe.src); + console.log('Profile sync iframe added with URL:', iframe.src); } function mczFrm_aquireFromStorage(lookupKey = null) { @@ -631,23 +624,23 @@ if ( async function mczFrm_saveRefs(baseAlias = null, refStorageKey = null) { if (!refStorageKey) { - console.warn("No reference storage key found"); + console.warn('No reference storage key found'); return; } let existingRefs = []; - let newRefs = []; + const newRefs = []; try { - existingRefs = JSON.parse(localStorage.getItem(refStorageKey) || "[]"); + existingRefs = JSON.parse(localStorage.getItem(refStorageKey) || '[]'); } catch (e) { - console.warn("Error parsing refStorage", e); + console.warn('Error parsing refStorage', e); existingRefs = []; } const dataProfileKeys = existingRefs || []; const now = new Date().getTime(); - for (let key of dataProfileKeys) { + for (const key of dataProfileKeys) { const lookupKey = key; let itemStr = null; itemStr = sessionStorage.getItem(lookupKey); @@ -679,22 +672,22 @@ if ( } if ( - baseAlias != null && - newRefs.indexOf(baseAlias) == -1 && - existingRefs.indexOf(baseAlias) == -1 + baseAlias != null + && newRefs.indexOf(baseAlias) == -1 + && existingRefs.indexOf(baseAlias) == -1 ) { newRefs.push(baseAlias); } localStorage.setItem(refStorageKey, JSON.stringify(newRefs)); - console.log("MCZ RefData: Updated refs in refStorage", newRefs); + console.log('MCZ RefData: Updated refs in refStorage', newRefs); } async function mczFrm_saveMsg(message) { try { const saveAlias = message?.alias || null; const refStorageKey = message?.refStorage || null; - const location = message?.location || "local"; + const location = message?.location || 'local'; const dataStr = JSON.stringify(message); const sizeInBytes = new Blob([dataStr]).size; const sizeInMB = sizeInBytes / (1024 * 1024); @@ -703,84 +696,82 @@ if ( console.warn(`MCZ RefData: Large data size (${sizeInMB.toFixed(2)}MB)`); } if (!saveAlias) { - console.warn("No save alias found"); + console.warn('No save alias found'); return; } - if (location == "session") { + if (location == 'session') { sessionStorage.setItem(saveAlias, dataStr); } else { localStorage.setItem(saveAlias, dataStr); } - console.log("MCZ RefData: Saved message:", message); + console.log('MCZ RefData: Saved message:', message); mczFrm_saveRefs(saveAlias, refStorageKey); } catch (storageError) { - console.warn("Storage error:", storageError); + console.warn('Storage error:', storageError); } } - async function mczFrm_saveSnapshot(target_path = "root.program") { + async function mczFrm_saveSnapshot(target_path = 'root.program') { let snapshot = {}; - let base = window?.mcz_marketoForm_pref || null; + const base = window?.mcz_marketoForm_pref || null; if (base == null) { - console.log("No base found, skipping snapshot."); + console.log('No base found, skipping snapshot.'); return; } - let pageFromEventId = base?.program?.event?.id || ""; - let programIDOnly = pageFromEventId?.replace(/[^0-9]/g, "") || ""; - if (programIDOnly == "") { - console.log("No event id found, skipping snapshot."); + const pageFromEventId = base?.program?.event?.id || ''; + const programIDOnly = pageFromEventId?.replace(/[^0-9]/g, '') || ''; + if (programIDOnly == '') { + console.log('No event id found, skipping snapshot.'); return; } - if (target_path == "root.program_profile") { + if (target_path == 'root.program_profile') { snapshot = base.program_profile; - } else if (target_path == "root.profile") { + } else if (target_path == 'root.profile') { snapshot = base.profile; - } else if (target_path == "root.form") { + } else if (target_path == 'root.form') { snapshot = base.form; - } else if (target_path == "root.program") { + } else if (target_path == 'root.program') { snapshot = base.program; - } else if (target_path == "root.program.event") { + } else if (target_path == 'root.program.event') { snapshot = base.program.event; } mczFrm_saveMsg({ alias: `pr_${programIDOnly}_`, - location: "local", + location: 'local', data: JSON.parse(JSON.stringify(snapshot)), }); } - window.addEventListener("message", (event) => { - let config = { - allowedOrigins: ["https://engage.adobe.com", "https://business.adobe.com"], - }; - let eventOrigin = new URL(event.origin); + window.addEventListener('message', (event) => { + const config = { allowedOrigins: ['https://engage.adobe.com', 'https://business.adobe.com'] }; + const eventOrigin = new URL(event.origin); let allowedToPass = false; for (let i = 0; i < config.allowedOrigins.length; i++) { - let allowedOriginURL = new URL(config.allowedOrigins[i]); + const allowedOriginURL = new URL(config.allowedOrigins[i]); if ( - eventOrigin.host === allowedOriginURL.host && - eventOrigin.protocol === allowedOriginURL.protocol && - eventOrigin.port === allowedOriginURL.port + eventOrigin.host === allowedOriginURL.host + && eventOrigin.protocol === allowedOriginURL.protocol + && eventOrigin.port === allowedOriginURL.port ) { allowedToPass = true; break; } } - if (event.data && event?.data?.type !== "mcz_marketoForm_pref_sync") { + if (event.data && event?.data?.type !== 'mcz_marketoForm_pref_sync') { allowedToPass = false; } if (!allowedToPass) { return; } - console.log("MCZ RefData Received:", event.data); + console.log('MCZ RefData Received:', event.data); if (event.data && event?.data?.target_path !== null && event?.data?.target_attribute !== null) { - let save = event?.data?.save || false; + const save = event?.data?.save || false; mczFrm_updateDL(event?.data); if (save) { mczFrm_saveMsg(event?.data); @@ -790,24 +781,22 @@ if ( function crawlAndUpdateObject(thisObject = null, targetObject = null) { if (thisObject == null || targetObject == null) { - console.warn("No object to crawl or update"); + console.warn('No object to crawl or update'); return; } - let this_data = JSON.parse(JSON.stringify(thisObject)); - for (let key in this_data) { + const this_data = JSON.parse(JSON.stringify(thisObject)); + for (const key in this_data) { if (targetObject.hasOwnProperty(key)) { - if (this_data[key] != null && this_data[key] != "" && this_data[key] != 0) { - if (typeof this_data[key] == "object") { + if (this_data[key] != null && this_data[key] != '' && this_data[key] != 0) { + if (typeof this_data[key] === 'object') { crawlAndUpdateObject(this_data[key], targetObject[key]); - } else { - if ( - targetObject[key] == null || - targetObject[key] == "" || - targetObject[key] == 0 || - targetObject[key] == "NULL" - ) { - targetObject[key] = this_data[key]; - } + } else if ( + targetObject[key] == null + || targetObject[key] == '' + || targetObject[key] == 0 + || targetObject[key] == 'NULL' + ) { + targetObject[key] = this_data[key]; } } } @@ -818,80 +807,79 @@ if ( if (data == null) { return; } - let targetPath = data?.target_path || null; + const targetPath = data?.target_path || null; if (targetPath == null) { return; } - let program_type = data?.data?.program?.type || "default"; - let program_status = "default"; + let program_type = data?.data?.program?.type || 'default'; + let program_status = 'default'; - let this_data = JSON.parse(JSON.stringify(data?.data)); - if (targetPath == "root.program_profile") { + const this_data = JSON.parse(JSON.stringify(data?.data)); + if (targetPath == 'root.program_profile') { window.mcz_marketoForm_pref.program_profile = this_data; - //crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.program_profile); - } else if (targetPath == "root.profile") { - //window.mcz_marketoForm_pref.profile = this_data; + // crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.program_profile); + } else if (targetPath == 'root.profile') { + // window.mcz_marketoForm_pref.profile = this_data; crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.profile); - } else if (targetPath == "root.form") { + } else if (targetPath == 'root.form') { window.mcz_marketoForm_pref.form = this_data; - //crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.form); - } else if (targetPath == "root.profile.acc") { + // crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.form); + } else if (targetPath == 'root.profile.acc') { window.mcz_marketoForm_pref.profile.acc = this_data; - //crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.profile.acc); - } else if (targetPath == "root.program") { + // crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.profile.acc); + } else if (targetPath == 'root.program') { window.mcz_marketoForm_pref.program = this_data; - //crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.program); - program_type = this_data?.type || "default"; - } else if (targetPath == "root.program.event") { + // crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.program); + program_type = this_data?.type || 'default'; + } else if (targetPath == 'root.program.event') { window.mcz_marketoForm_pref.program.event = this_data; - //crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.program.event); - program_type = this_data?.type || "default"; + // crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.program.event); + program_type = this_data?.type || 'default'; } - if (window.mcz_marketoForm_pref?.program?.type == "event") { + if (window.mcz_marketoForm_pref?.program?.type == 'event') { mczFrm_updateTimeUntil(); - if (window.mcz_marketoForm_pref?.program?.event?.type == "adobe_connect") { - program_type = "adobe_connect"; - program_status = - window.mcz_marketoForm_pref?.program?.event?.adobe_connect?.status?.overall || "pending"; + if (window.mcz_marketoForm_pref?.program?.event?.type == 'adobe_connect') { + program_type = 'adobe_connect'; + program_status = window.mcz_marketoForm_pref?.program?.event?.adobe_connect?.status?.overall || 'pending'; } } - function mczFrm_statusLbls(program_type = "", program_status = "") { - if (program_type == "" || program_status == "") { - console.log("No program type or status found"); + function mczFrm_statusLbls(program_type = '', program_status = '') { + if (program_type == '' || program_status == '') { + console.log('No program type or status found'); return; } - let dataLabel = "data-mcz-dl-status"; - let elements = document.querySelectorAll(`[${dataLabel}]`); - let timeNow = new Date().getTime(); + const dataLabel = 'data-mcz-dl-status'; + const elements = document.querySelectorAll(`[${dataLabel}]`); + const timeNow = new Date().getTime(); for (let i = 0; i < elements.length; i++) { - let element = elements[i]; + const element = elements[i]; element.setAttribute(`${dataLabel}-dt`, timeNow); element.setAttribute(`${dataLabel}-type`, program_type); element.setAttribute(`${dataLabel}`, program_status); } } - console.log("Status Labels:", program_type, program_status); + console.log('Status Labels:', program_type, program_status); mczFrm_statusLbls(program_type, program_status); } - function mczFrm_sendMessage(targetPath = "root.program", data = {}) { - let iframe = document.getElementById("mcz-marketo-program-iframe"); + function mczFrm_sendMessage(targetPath = 'root.program', data = {}) { + const iframe = document.getElementById('mcz-marketo-program-iframe'); if (iframe) { - if (JSON.stringify(data) == "{}") { + if (JSON.stringify(data) == '{}') { data = { - type: "mcz_marketoForm_pref_sync", + type: 'mcz_marketoForm_pref_sync', target_path: targetPath, }; } - iframe.contentWindow.postMessage(data, "https://engage.adobe.com"); + iframe.contentWindow.postMessage(data, 'https://engage.adobe.com'); } else { - console.warn("No iframe found"); + console.warn('No iframe found'); } } @@ -940,19 +928,19 @@ if ( let maxTries = 1000; export function CheckResourceLocation(el, resourceWatch, resourceLocation) { if (maxTries <= 0) { - console.log("maxTries reached", maxTries); + console.log('maxTries reached', maxTries); return; } maxTries--; - if (document.querySelector(resourceWatch)) { - setTimeout(() => { - console.log("Resource found, loading..."); - mczFrm_mkto_testing_loader(el, resourceLocation); - }, 1000); - } else { - setTimeout(() => { - console.log("Resource not found, checking again..."); - CheckResourceLocation(el, resourceWatch, resourceLocation); - }, 20); - } -}; \ No newline at end of file + if (document.querySelector(resourceWatch)) { + setTimeout(() => { + console.log('Resource found, loading...'); + mczFrm_mkto_testing_loader(el, resourceLocation); + }, 1000); + } else { + setTimeout(() => { + console.log('Resource not found, checking again...'); + CheckResourceLocation(el, resourceWatch, resourceLocation); + }, 20); + } +} From 754545c27d5e6028baaa463c572d11979234b350 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Thu, 31 Jul 2025 17:16:30 +0530 Subject: [PATCH 89/93] minor review comment --- events/blocks/mcz-handler/mcz-handler.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/events/blocks/mcz-handler/mcz-handler.js b/events/blocks/mcz-handler/mcz-handler.js index 82ab18b0..9585328c 100644 --- a/events/blocks/mcz-handler/mcz-handler.js +++ b/events/blocks/mcz-handler/mcz-handler.js @@ -45,10 +45,7 @@ export default async function init(el) { const status = el.getAttribute('data-mcz-dl-status'); // TODO: remove this console.log post validation with marketo integration. - console.log( - 'Attribute "data-mcz-dl-status" changed to', - el.getAttribute('data-mcz-dl-status'), - ); + console.log('Attribute "data-mcz-dl-status" changed to', status); if (status === 'active') { mczMarketoFormAdobeConnectEvent(); } From 93374ff77d1deeab0ccafb2246699f497b2d798d Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Thu, 21 Aug 2025 13:03:27 +0530 Subject: [PATCH 90/93] Script update --- rs/360-KCI-804/images/mktoTestFormConfig.js | 215 +++++++++++++------- 1 file changed, 143 insertions(+), 72 deletions(-) diff --git a/rs/360-KCI-804/images/mktoTestFormConfig.js b/rs/360-KCI-804/images/mktoTestFormConfig.js index 8580eb7a..4abea660 100644 --- a/rs/360-KCI-804/images/mktoTestFormConfig.js +++ b/rs/360-KCI-804/images/mktoTestFormConfig.js @@ -93,7 +93,7 @@ if ( let marketoConfiguratorJSON = {}; try { marketoConfiguratorJSON = JSON.parse( - decodeURIComponent(escape(window.atob(marketoConfiguratorLink))), + decodeURIComponent(escape(window.atob(marketoConfiguratorLink))) ); } catch (e) { console.error('Error parsing Marketo Configurator JSON', e); @@ -212,38 +212,38 @@ if ( window.mcz_marketoForm_pref = JSON.parse(JSON.stringify(mcz_marketoForm_pref_local)); const loadScript = (url, type, { mode } = {}) => new Promise((resolve, reject) => { - let script = document.querySelector(`head > script[src="${url}"]`); - if (!script) { - const { head } = document; + let script = document.querySelector(`head > script[src="${url}"]`); + if (!script) { + const { head } = document; script = document.createElement('script'); script.setAttribute('src', url); - if (type) { + if (type) { script.setAttribute('type', type); - } + } if (['async', 'defer'].includes(mode)) script.setAttribute(mode, true); - head.append(script); - } + head.append(script); + } - if (script.dataset.loaded) { - resolve(script); - return; - } + if (script.dataset.loaded) { + resolve(script); + return; + } - const onScript = (event) => { + const onScript = (event) => { script.removeEventListener('load', onScript); script.removeEventListener('error', onScript); if (event.type === 'error') { - reject(new Error(`error loading script: ${script.src}`)); + reject(new Error(`error loading script: ${script.src}`)); } else if (event.type === 'load') { - script.dataset.loaded = true; - resolve(script); - } - }; + script.dataset.loaded = true; + resolve(script); + } + }; script.addEventListener('load', onScript); script.addEventListener('error', onScript); - }); + }); const resourceForm = document.createElement('div'); resourceForm.innerHTML = resourceFormHTML; @@ -317,6 +317,8 @@ if ( } else { console.log('no resource with attribute data-mcz-dl-status found'); } + + mczFrm_updateTimeUntil(); }; // @@ -511,6 +513,7 @@ if ( console.log('timeUntilStart', timeUntilStart); if (timeUntilStart.minutes <= 30) { + mczFrm_saveSnapshot("root.program.event"); if (!timeUntilInterval) { timeUntilInterval = setInterval(mczFrm_updateTimeUntil, 1000); } @@ -592,13 +595,15 @@ if ( console.log('Profile sync iframe added with URL:', iframe.src); } - function mczFrm_aquireFromStorage(lookupKey = null) { + function mczFrm_aquireFromStorage(lookupKey = null, updateWith = null) { const now = new Date().getTime(); + let locationWas = 'session'; let itemStr = null; itemStr = sessionStorage.getItem(lookupKey); if (!itemStr) { itemStr = localStorage.getItem(lookupKey); + locationWas = 'local'; } if (!itemStr) { return null; @@ -616,6 +621,19 @@ if ( console.log(`MCZ RefData: Expired program removed from ${lookupKey}`); return null; } + if (updateWith) { + item.location = locationWas; + item.timestamp = now; + item.expires = now + shelfLife; + item.data = updateWith; + itemStr = JSON.stringify(item); + if (locationWas == 'session') { + sessionStorage.setItem(lookupKey, itemStr); + } else { + localStorage.setItem(lookupKey, itemStr); + } + console.log("MCZ RefData: Updated snapshot in", locationWas, lookupKey); + } return item; } catch (e) { return null; @@ -714,38 +732,62 @@ if ( } } - async function mczFrm_saveSnapshot(target_path = 'root.program') { - let snapshot = {}; + async function mczFrm_saveSnapshot(targetPath = 'root.program.event') { const base = window?.mcz_marketoForm_pref || null; - if (base == null) { - console.log('No base found, skipping snapshot.'); - return; - } - const pageFromEventId = base?.program?.event?.id || ''; const programIDOnly = pageFromEventId?.replace(/[^0-9]/g, '') || ''; if (programIDOnly == '') { console.log('No event id found, skipping snapshot.'); return; } + targetPath = targetPath.toLowerCase().trim(); + const syncActions = { + 'root.program': 'program', + 'root.program_profile': 'program_profile', + 'root.program.event': 'event', + 'root.profile': 'profile', + 'root.profile.acc': 'profile_acc', + 'root.form': 'form', + 'root.landingPage': 'landingPage', + }; - if (target_path == 'root.program_profile') { - snapshot = base.program_profile; - } else if (target_path == 'root.profile') { - snapshot = base.profile; - } else if (target_path == 'root.form') { - snapshot = base.form; - } else if (target_path == 'root.program') { - snapshot = base.program; - } else if (target_path == 'root.program.event') { - snapshot = base.program.event; - } + if (syncActions[targetPath]) { + let snapshot = {}; + if (base == null) { + console.warn('mczFrm_saveSnapshot: No base found'); + return; + } + const targetPathRef = (targetPath?.split(".")?.pop() || '').toLowerCase().trim(); + const saveAlias = base?.sync_profiles?.data_profiles?.[targetPathRef]?.ref || null; + const host = base?.sync_profiles?.data_profiles?.[targetPathRef]?.host || null; + + if (host == null) { + console.warn('mczFrm_saveSnapshot: No host found for', targetPath); + return; + } + if (saveAlias == null) { + console.warn('mczFrm_saveSnapshot: No save alias found for', targetPath); + return; + } + const hostRef = (host?.split('.')?.pop() || '').toLowerCase().trim(); + snapshot = base[hostRef] || {}; - mczFrm_saveMsg({ - alias: `pr_${programIDOnly}_`, - location: 'local', - data: JSON.parse(JSON.stringify(snapshot)), - }); + if (Object.keys(snapshot).length == 0) { + console.warn('mczFrm_saveSnapshot: snapshot is empty for', targetPath); + return; + } + + const existingSnapshot = mczFrm_aquireFromStorage(saveAlias, snapshot); + if (existingSnapshot) { + console.log( + 'mczFrm_saveSnapshot: Existing snapshot found and updated with', + existingSnapshot + ); + return; + } + } else { + console.warn('mczFrm_saveSnapshot: targetPath not found', targetPath); + } } window.addEventListener('message', (event) => { @@ -779,26 +821,54 @@ if ( } }); - function crawlAndUpdateObject(thisObject = null, targetObject = null) { + function crawlAndUpdateObject( + thisObject = null, + targetObject = null, + shouldOverwrite = true, + addToTarget = true + ) { if (thisObject == null || targetObject == null) { console.warn('No object to crawl or update'); return; } - const this_data = JSON.parse(JSON.stringify(thisObject)); - for (const key in this_data) { - if (targetObject.hasOwnProperty(key)) { - if (this_data[key] != null && this_data[key] != '' && this_data[key] != 0) { - if (typeof this_data[key] === 'object') { - crawlAndUpdateObject(this_data[key], targetObject[key]); - } else if ( - targetObject[key] == null - || targetObject[key] == '' - || targetObject[key] == 0 - || targetObject[key] == 'NULL' - ) { - targetObject[key] = this_data[key]; - } - } + + const isSourceMeaningful = (value) => { + if (value === null || value === undefined) return false; + if (value === "") return false; + if (value === 0 || value === false) return false; // preserve original loose `!= 0` semantics + return true; + }; + + const isTargetEmpty = (value) => { + return ( + value === null || + value === undefined || + value === "" || + value === 0 || + value === false || + value === "NULL" + ); + }; + + const isObjectLike = (value) => typeof value === 'object' && value !== null; + + for (const key of Object.keys(thisObject)) { + if (!Object.prototype.hasOwnProperty.call(targetObject, key) && !addToTarget) { + continue; + } + const sourceVal = thisObject[key]; + if (!isSourceMeaningful(sourceVal)) { + continue; + } + + const targetVal = targetObject[key]; + if (isObjectLike(sourceVal) && isObjectLike(targetVal)) { + crawlAndUpdateObject(sourceVal, targetVal, shouldOverwrite, addToTarget); + continue; + } + + if (isTargetEmpty(targetVal) || shouldOverwrite) { + targetObject[key] = sourceVal; } } } @@ -817,23 +887,23 @@ if ( const this_data = JSON.parse(JSON.stringify(data?.data)); if (targetPath == 'root.program_profile') { window.mcz_marketoForm_pref.program_profile = this_data; - // crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.program_profile); - } else if (targetPath == 'root.profile') { - // window.mcz_marketoForm_pref.profile = this_data; - crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.profile); - } else if (targetPath == 'root.form') { + //crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.program_profile, true, true); + } else if (targetPath === 'root.profile') { + window.mcz_marketoForm_pref.profile = this_data; + //crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.profile, true, true); + } else if (targetPath === 'root.form') { window.mcz_marketoForm_pref.form = this_data; - // crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.form); - } else if (targetPath == 'root.profile.acc') { + crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.form, true, true); + } else if (targetPath === 'root.profile.acc') { window.mcz_marketoForm_pref.profile.acc = this_data; - // crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.profile.acc); - } else if (targetPath == 'root.program') { + //crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.profile.acc, true, true); + } else if (targetPath === 'root.program') { window.mcz_marketoForm_pref.program = this_data; - // crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.program); + //crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.program); program_type = this_data?.type || 'default'; - } else if (targetPath == 'root.program.event') { + } else if (targetPath === 'root.program.event') { window.mcz_marketoForm_pref.program.event = this_data; - // crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.program.event); + //crawlAndUpdateObject(this_data, window.mcz_marketoForm_pref.program.event); program_type = this_data?.type || 'default'; } @@ -841,7 +911,8 @@ if ( mczFrm_updateTimeUntil(); if (window.mcz_marketoForm_pref?.program?.event?.type == 'adobe_connect') { program_type = 'adobe_connect'; - program_status = window.mcz_marketoForm_pref?.program?.event?.adobe_connect?.status?.overall || 'pending'; + program_status = + window.mcz_marketoForm_pref?.program?.event?.adobe_connect?.status?.overall || "pending"; } } From c4f7c1a01e516011b533d38632dc936a9d3895d8 Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Thu, 21 Aug 2025 15:11:02 +0530 Subject: [PATCH 91/93] adding support for mczID flow --- events/blocks/mcz-handler/mcz-handler.js | 9 ++++++++- rs/360-KCI-804/images/mktoTestFormConfig.js | 20 +++++++++++--------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/events/blocks/mcz-handler/mcz-handler.js b/events/blocks/mcz-handler/mcz-handler.js index 9585328c..9cee3f66 100644 --- a/events/blocks/mcz-handler/mcz-handler.js +++ b/events/blocks/mcz-handler/mcz-handler.js @@ -13,7 +13,14 @@ export default async function init(el) { el.setAttribute('data-mcz-dl-status', 'loading'); - await CheckResourceLocation(el, resourceWatch, resourceLocation); + let mczId = null; + if (getMetadata('eventExternalId')) { + const eventExternalId = getMetadata('eventExternalId'); + //split the eventExternalId by - and get the last part + mczId = eventExternalId.replace('-', '').toLowerCase(); + } + + await CheckResourceLocation(el, resourceWatch, resourceLocation, mczId); async function mczMarketoFormAdobeConnectEvent() { if (window.mcz_marketoForm_pref?.form?.success?.type === 'adobe_connect') { diff --git a/rs/360-KCI-804/images/mktoTestFormConfig.js b/rs/360-KCI-804/images/mktoTestFormConfig.js index 4abea660..525366a8 100644 --- a/rs/360-KCI-804/images/mktoTestFormConfig.js +++ b/rs/360-KCI-804/images/mktoTestFormConfig.js @@ -49,7 +49,7 @@ if ( const BASE_URL = 'https://engage.marketo.com'; const MUNCHKIN_ID = '360-KCI-804'; - var mczFrm_mkto_testing_loader = (el, resourceLocation) => { + var mczFrm_mkto_testing_loader = (el, resourceLocation, mczId = null) => { const cssFast = ` button[daa-ll="Join the event-1--"] { visibility: hidden !important; @@ -136,7 +136,7 @@ if ( event: { type: 'adobe_connect', // connect_recording or video subtype: 'flex_event', - id: 'mcz114328', + id: mczId ?? 'mcz114328', status: { viewport: { width: 1024, @@ -215,12 +215,14 @@ if ( let script = document.querySelector(`head > script[src="${url}"]`); if (!script) { const { head } = document; - script = document.createElement('script'); - script.setAttribute('src', url); + script = document.createElement('script'); + script.setAttribute('src', url); if (type) { - script.setAttribute('type', type); + script.setAttribute('type', type); } - if (['async', 'defer'].includes(mode)) script.setAttribute(mode, true); + + if (['async', 'defer'].includes(mode)) script.setAttribute(mode, true); + head.append(script); } @@ -997,7 +999,7 @@ if ( // ## // ## let maxTries = 1000; -export function CheckResourceLocation(el, resourceWatch, resourceLocation) { +export function CheckResourceLocation(el, resourceWatch, resourceLocation, mczId = null) { if (maxTries <= 0) { console.log('maxTries reached', maxTries); return; @@ -1006,12 +1008,12 @@ export function CheckResourceLocation(el, resourceWatch, resourceLocation) { if (document.querySelector(resourceWatch)) { setTimeout(() => { console.log('Resource found, loading...'); - mczFrm_mkto_testing_loader(el, resourceLocation); + mczFrm_mkto_testing_loader(el, resourceLocation, mczId); }, 1000); } else { setTimeout(() => { console.log('Resource not found, checking again...'); - CheckResourceLocation(el, resourceWatch, resourceLocation); + CheckResourceLocation(el, resourceWatch, resourceLocation, mczId); }, 20); } } From 71eed3df769efd782ebf0f6fa855e8b9723be00c Mon Sep 17 00:00:00 2001 From: Gautam Bajaj Date: Thu, 21 Aug 2025 21:01:26 +0530 Subject: [PATCH 92/93] minor fix --- events/blocks/mcz-handler/mcz-handler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/events/blocks/mcz-handler/mcz-handler.js b/events/blocks/mcz-handler/mcz-handler.js index 9cee3f66..f4c962f6 100644 --- a/events/blocks/mcz-handler/mcz-handler.js +++ b/events/blocks/mcz-handler/mcz-handler.js @@ -1,5 +1,5 @@ import { CheckResourceLocation } from '../../../rs/360-KCI-804/images/mktoTestFormConfig.js'; -import { setMetadata } from '../../scripts/utils.js'; +import { setMetadata, getMetadata } from '../../scripts/utils.js'; export default async function init(el) { const rows = Array.from(el.children); From e851803a44866ccea7864516f895d575f0c2e935 Mon Sep 17 00:00:00 2001 From: Qiyun Dai Date: Wed, 27 Aug 2025 13:18:49 -0400 Subject: [PATCH 93/93] Quick lint --- events/blocks/adobe-connect/adobe-connect.js | 16 ++++++++-------- events/blocks/mcz-handler/mcz-handler.js | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/events/blocks/adobe-connect/adobe-connect.js b/events/blocks/adobe-connect/adobe-connect.js index afbeb2f7..8130808e 100644 --- a/events/blocks/adobe-connect/adobe-connect.js +++ b/events/blocks/adobe-connect/adobe-connect.js @@ -2,7 +2,7 @@ import { LIBS, getMetadata } from '../../scripts/utils.js'; const { createTag } = await import(`${LIBS}/utils/utils.js`); - //TODO: remove post validation with marketo integration. +// TODO: remove post validation with marketo integration. function addParams(searchParams, params, key, value) { if (params.has(key)) { searchParams[key] = params.get(key); @@ -11,16 +11,18 @@ function addParams(searchParams, params, key, value) { } } - //TODO: remove post validation with marketo integration. +// TODO: remove post validation with marketo integration. function addSearchParams(url, searchParams) { const urlObj = new URL(url); - for (const [key, value] of Object.entries(searchParams)) { + + Object.entries(searchParams).forEach(([key, value]) => { urlObj.searchParams.append(key, value); - } + }); + return urlObj.toString(); } - //TODO: remove post validation with marketo integration. +// TODO: remove post validation with marketo integration. function getSearchParamsFromCurrentUrl() { const params = new URL(window.location.href).searchParams; const searchParams = {}; @@ -120,8 +122,6 @@ export default async function init(el) { overlayElem.classList.add('hidden'); } - - if (getMetadata('adobe-connect-url')) { url = getMetadata('adobe-connect-url'); } else { @@ -129,7 +129,7 @@ export default async function init(el) { return; } - //TODO: remove post validation with marketo integration. + // TODO: remove post validation with marketo integration. const searchParams = getSearchParamsFromCurrentUrl(); url = addSearchParams(url, searchParams); diff --git a/events/blocks/mcz-handler/mcz-handler.js b/events/blocks/mcz-handler/mcz-handler.js index f4c962f6..9f7dca1e 100644 --- a/events/blocks/mcz-handler/mcz-handler.js +++ b/events/blocks/mcz-handler/mcz-handler.js @@ -16,7 +16,7 @@ export default async function init(el) { let mczId = null; if (getMetadata('eventExternalId')) { const eventExternalId = getMetadata('eventExternalId'); - //split the eventExternalId by - and get the last part + // split the eventExternalId by - and get the last part mczId = eventExternalId.replace('-', '').toLowerCase(); }