app-staging.skillfit.me
Open in
urlscan Pro
13.32.151.80
Public Scan
URL:
https://app-staging.skillfit.me/
Submission: On December 26 via api from US — Scanned from US
Submission: On December 26 via api from US — Scanned from US
Form analysis
0 forms found in the DOMText Content
(function () { // baseUrl DYNAMICALLY CHANGED - DO NOT CHANGE THIS UNLESS YOU CHANGE iframe_copy_script.js AS WELL const baseUrl = 'https://embed-staging.skillfit.me'; const SCRIPT_ATTRIBUTE_CLIENT_ID_KEY = 'data-emsi-client-id'; const TARGET_PATH_QUERY_PARAM_KEY = '_z'; const TARGET_DIV_ID = 'emsi-skills-div-app-001'; const IFRAME_ID = 'emsi-skills-iframe-app-001'; const SLASH_DELIMITER = '--'; const EMSI_APP_NAME = 'Emsi skill app'; const SEARCH_QUERY_PARAM_KEY = '_s'; // DO NOT UPDATE WITHOUT also updating iFrameCommunication.ts const EQUAL_SIGN_PLACEHOLDER = '1*0_0*1'; // DO NOT UPDATE WITHOUT also updating iFrameCommunication.ts const AMPERSAND_PLACEHOLDER = '-4*7_'; // DO NOT UPDATE WITHOUT also updating iFrameCommunication.ts const QUESTION_MARK_PLACEHOLDER = '0.._-..0'; // DO NOT UPDATE WITHOUT also updating iFrameCommunication.ts const EVENT_NAME_URL_CHANGE = 'urlChange'; const EVENT_NAME_SET_WINDOW_SCROLL_POSITION = 'setWindowScrollPosition'; const EVENT_NAME_GO_TO_WINDOW_SCROLL_POSITION = 'goToWindowScrollPosition'; function checkIfInJest() { return typeof jest !== 'undefined'; } const getSanitizedURLSearch = (search) => { // we want to pass `search` from the caller to decide what to do between `decodeURIComponent` and `encodeURIComponent` // example: converting `--` to `%2F` or vise versa while (search.startsWith('?') || search.startsWith('%3F')) { if (search.startsWith('?')) { search = search.replace('?', ''); } else { search = search.replace('%3F', ''); } } const searchObject = new URLSearchParams(search); return searchObject; }; function handleBrowserNavigation() { console.log(`handleBrowserNavigation:popstate()`, window); window.addEventListener('popstate', (event) => { if (!window.haltPopState) { console.log( 'iframe.js:window.POPSTATE::::: location: ' + document.location + ', state: ' + JSON.stringify(event.state) ); console.log(`window.iframeResizer`, window.iframeResizer); const formattedSearch = convertSlashReplacements(window.location.search); const params = formattedSearch ? getSanitizedURLSearch(formattedSearch) : new URLSearchParams(); const path = params.get(TARGET_PATH_QUERY_PARAM_KEY) || ''; params.delete(TARGET_PATH_QUERY_PARAM_KEY); const newRouteForIFrameChild = `${path}?${params.toString()}`; window.iframeResizer[0].iFrameResizer.sendMessage( { eventName: 'browser_navigation_back', newRoute: newRouteForIFrameChild, }, ['*'] ); // SUPERHACK: Firefox, for whatever reason, wants to fire off an additional POPSTATE once we call `window.history.go(-2)` down below // This is to prevent a rapid chain of navigations. window.haltPopState = true; setTimeout(() => (window.haltPopState = false), 250); } }); } /** * Converts our slash delimiter to html encoded slashes ('%2F' === `/`) * '_z=account--sign-in' -> _z=account%2Fsign-in */ function convertSlashReplacements(param) { const replaceAll = (str, find, rep) => str.split(find).join(rep); return replaceAll(param, SLASH_DELIMITER, '%2F'); } function addScript(src, callback) { var s = document.createElement('script'); s.setAttribute('src', src); s.onload = callback; s.onerror = function () { console.error(`failed to load iframe resizer script`); }; document.getElementsByTagName('head')[0].appendChild(s); } function getClientId() { var thisScript = document.querySelector(`script[${SCRIPT_ATTRIBUTE_CLIENT_ID_KEY}]`); if (!thisScript) { console.error( `${SCRIPT_ATTRIBUTE_CLIENT_ID_KEY} key must exist. Add the ${SCRIPT_ATTRIBUTE_CLIENT_ID_KEY}=<emsi id> data attribute to your script tag` ); return false; } const clientId = thisScript.getAttribute(SCRIPT_ATTRIBUTE_CLIENT_ID_KEY); if (!clientId) { console.error(`${SCRIPT_ATTRIBUTE_CLIENT_ID_KEY} key was empty. Populate your client id`); return; } return clientId; } /** * Create iframe.src variable. Allow empty _z key. */ function constructIframeSource() { const formattedSearch = convertSlashReplacements(window.location.search); const urlParams = getSanitizedURLSearch(formattedSearch); const path = urlParams.get(TARGET_PATH_QUERY_PARAM_KEY) || ''; // empty string so we don't add `null` to url const hashedSearchParams = urlParams.get(SEARCH_QUERY_PARAM_KEY); if (hashedSearchParams) { const appSearchParams = new URLSearchParams( hashedSearchParams .replaceAll(EQUAL_SIGN_PLACEHOLDER, '=') .replaceAll(AMPERSAND_PLACEHOLDER, '&') .replaceAll(QUESTION_MARK_PLACEHOLDER, '?') ); for (const key of appSearchParams.keys()) { urlParams.delete(key); appSearchParams.getAll(key).forEach((value) => urlParams.append(key, value)); } } urlParams.append('parentLocation', window.location.origin + window.location.pathname); urlParams.append('clientId', getClientId()); urlParams.delete(TARGET_PATH_QUERY_PARAM_KEY); urlParams.delete(SEARCH_QUERY_PARAM_KEY); const queryParam = `?${urlParams.toString()}`; return `${baseUrl}/${path}${queryParam}`; } function mutateStyle(element) { element.style.border = '0'; element.style.minWidth = '100%'; element.style.width = '1px'; } function updateNavState(state = {}, unusedString = '', url) { // with replaceState, popState doesn't work, so we opted with pushState, and now we get double history // this is required because without it, the child iframe nav doesn't update the parent page nav, and so using // browser nav would be broken window.history.pushState(state, unusedString, url); } function onUrlChangeMessage(message) { console.info(`Attempting to update parent query params with: ${JSON.stringify(message)}`); const { newAppPath, newAppSearchQueryString, title, isNavigatingBack } = message; const currUrlParams = getSanitizedURLSearch(window.location.search); const iframe = document.getElementById(IFRAME_ID); // If statement is an Edge case in which the iFrame is still being intialized if (iframe) { iframe.title = `SkillFit - ${title}`; } currUrlParams.set(TARGET_PATH_QUERY_PARAM_KEY, newAppPath); if (newAppSearchQueryString) { currUrlParams.set(SEARCH_QUERY_PARAM_KEY, newAppSearchQueryString); } else { currUrlParams.delete(SEARCH_QUERY_PARAM_KEY); } const fullPath = `${window.location.origin}${window.location.pathname}${ currUrlParams.toString().length ? '?' + currUrlParams.toString().replace(/%2F/g, SLASH_DELIMITER) : '' }`; if (isNavigatingBack) { console.info('Navigating back'); // to avoid the problem of double history being recorded window.history.go(-2); } else { console.info(`Parent url update: `, fullPath); updateNavState({ title }, '', fullPath); } } function setWindowScrollPosition() { const scrollPosition = { scrollX: window.scrollX, scrollY: window.scrollY }; window.__iframe_temp_store = { scrollPosition }; } function scrollToWindowScrollPosition() { const scrollPosition = (window.__iframe_temp_store || {}).scrollPosition; if (!scrollPosition) { return; } window.scrollTo(scrollPosition.scrollX, scrollPosition.scrollY); window.__iframe_temp_store = { scrollPosition: undefined }; } function createIframe() { const src = constructIframeSource(); console.log(`src`, src); if (!src) { console.error(`${EMSI_APP_NAME} could not find url param. Make sure you create a url with a valid route`); return false; } var iframe = document.createElement('iframe'); iframe.src = src; iframe.id = IFRAME_ID; iframe.title = 'SkillFit'; mutateStyle(iframe); const parentDiv = document.getElementById(TARGET_DIV_ID); mutateStyle(parentDiv); if (!parentDiv) { console.error( `${EMSI_APP_NAME} could not find target div element. Make sure you create a div with the id ${TARGET_DIV_ID}` ); return false; } parentDiv.appendChild(iframe); return true; } function hasES6support() { try { Function('() => {};'); return true; } catch (exception) { return false; } } function setup() { if (checkIfInJest()) return; if (!hasES6support()) { console.error(`Your browser does not support required features. Try using chrome`); } const success = createIframe(); if (!success) { console.error(`${EMSI_APP_NAME} failed to load`); return; } addScript('https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.3.1/iframeResizer.min.js', function () { // iFrameResize() is included in the above-script... // eslint-disable-next-line no-undef window.iframeResizer = iFrameResize( { heightCalculationMethod: 'lowestElement', log: false, targetOrigin: '*', onMessage: function (param) { // this is triggered by the inframed page navigating const eventName = (param.message || {}).eventName; if (eventName === EVENT_NAME_URL_CHANGE) { if (param.message) { onUrlChangeMessage(param.message); } } else if (eventName === EVENT_NAME_SET_WINDOW_SCROLL_POSITION) { setWindowScrollPosition(); } else if (eventName === EVENT_NAME_GO_TO_WINDOW_SCROLL_POSITION) { scrollToWindowScrollPosition(); } else { console.warn(`Bad event name ${eventName}`); } }, }, `#${IFRAME_ID}` ); }); handleBrowserNavigation(); console.info(`${EMSI_APP_NAME} iframe initialized`); } setup(); // This is a hack for unit testing import, should probably rewrite to use webpack for bundling this file if we want to use more functions from here if (typeof exports === 'object') { module.exports = { onUrlChangeMessage }; } })();