Integration file¶
Source code of integration.js¶
integration.js file
const IFRAME_MAX_OFFSET = 0;
const THEME_MODE = {
DEFAULT: 'dark',
LIGHT: 'light',
DARK: 'dark',
};
let currentLang = 'en';
let currentThemeMode = localStorage.getItem('prefers-color-scheme');
let prevMountedUrl = null;
const configuration = {
languages: [currentLang],
blacklistedRoutes: ['/mini-iframe'],
};
const setThemeMode = (mode) => {
currentThemeMode = mode;
document.body.setAttribute('data-theme', mode);
localStorage.setItem('prefers-color-scheme', mode);
};
const emitThemeMode = () => {
module.emit({ mode: currentThemeMode }, 'theme-mode-change');
};
const toggleThemeMode = (mode) => {
if (mode) {
setThemeMode(mode);
} else {
setThemeMode(
currentThemeMode === THEME_MODE.LIGHT
? THEME_MODE.DARK
: THEME_MODE.LIGHT,
);
}
emitThemeMode();
};
const emitThemeName = (name) => {
module.emit({ name }, 'theme-mode-change');
};
const getUrlLang = (path, languages) =>
path
.split(/[/?]/)
.filter(Boolean)
.find((segment) => languages.includes(segment));
const getIframePosition = () => {
const iframeEl = document.getElementById('betbook');
return iframeEl?.getBoundingClientRect();
};
const postMessage = (value, type = 'iframe') => {
try {
window.frames.target.postMessage(
{
type,
value,
},
'*', // @todo use config.get(currentHost) later
);
} catch (e) {
console.error(e);
}
};
const handleScroll = () => {
module.emit({isScrollEnabled: getIframePosition()?.top > 0}, 'iframe-scroll');
}
const mount = (id, inputUrl, onLoadCallback = () => {}, attributes = {}) => {
const defaultAttributes = {
frameBorder: 0,
id: 'betbook',
class: 'betbook',
allow:
'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share',
};
const prevPath = module.getData('path');
const prevQuery = module.getData('query');
const [url, query = ''] = inputUrl.split('?');
let fullQuery = '';
if (query) {
fullQuery = `?${query}`;
}
let iframeUrl = url + fullQuery;
/** take lang from iframe url */
currentLang = getUrlLang(url, configuration.languages);
const { href, pathname } = new URL(window.location.href);
const hasLang = new RegExp(`/${currentLang}(/|\\?)`).test(href);
const currentLangSubstring = hasLang ? `/${currentLang}/` : '/';
const prefixedOrigin = `${window.origin}/${configuration.urlPrefix}`;
const hasSearchParams = href.indexOf('?') > 0;
const path =
prevPath ||
pathname.substring(
configuration.urlPrefix.length + currentLangSubstring.length + 1,
);
let search = '';
if (prevQuery) {
search = `${fullQuery ? '&' : '?'}${prevQuery}`;
} else if (hasSearchParams) {
const searchString = href.substring(href.indexOf('?') + 1);
search = `${fullQuery ? '&' : '?'}${searchString}`;
}
/** if page was refreshed when url is not home or unwanted redirect to home */
if (href.includes(prefixedOrigin) || (pathname === '/' && prevPath)) {
iframeUrl = url + path + fullQuery + search;
}
if (prevMountedUrl === iframeUrl) return null;
prevMountedUrl = iframeUrl;
const iframe = document.createElement('iframe');
iframe.setAttribute('src', iframeUrl);
iframe.setAttribute('name', 'target');
iframe.setAttribute('onload', onLoadCallback);
const props = { ...defaultAttributes, ...attributes };
Object.entries(props).forEach(([name, value]) => {
iframe.setAttribute(name, value);
});
try {
if (props.id && document.getElementById(props.id)) {
document.getElementById(props.id).setAttribute('src', iframeUrl);
} else {
document.getElementById(id).append(iframe);
}
} catch (e) {
console.error(e);
}
postMessage({ path: `/${path || ''}` }, 'iframe-navigation');
return iframe;
};
const messagePubSub = {
messages: new Map(),
subscribers: new Map(),
subscribe: (event, callback) => {
if (!messagePubSub.subscribers.has(event)) {
messagePubSub.subscribers.set(event, new Set());
}
const callbacks = messagePubSub.subscribers.get(event);
callbacks.add(callback);
return {
unsubscribe: () => {
callbacks.delete(callback);
if (callbacks.size === 0) {
messagePubSub.subscribers.delete(event);
}
},
};
},
notifySubscribers: (event, data) => {
const subscriberCallback = messagePubSub.subscribers.get(event);
if (subscriberCallback) {
subscriberCallback.forEach((cb) => cb(data));
}
},
};
window.addEventListener('message', ({ data }) => {
if (!data.type) return;
messagePubSub.notifySubscribers(data.type, data);
});
messagePubSub.subscribe('navigation', (data) => {
const { path, previousPath } = data;
const isEmptyPrevPath =
previousPath === undefined || previousPath === `/${currentLang}/`;
if (
configuration.isNavigationCaptureDisabled ||
!path ||
(path === '/' && isEmptyPrevPath) ||
path === `/${currentLang}/` ||
configuration.blacklistedRoutes.includes(path)
) {
return;
}
let query = '';
if (data.query instanceof Object && Object.keys(data.query).length !== 0) {
query = new URLSearchParams(data.query);
query.delete('jwt');
if (query.toString().length) {
query = `?${query.toString()}`;
}
}
const url =
path === '/'
? window.location.origin
: `${window.location.origin}/${configuration.urlPrefix}/${currentLang}${path}${query}`;
window.history.replaceState(null, document.title, url);
module.setData({ path: `${path}`.substring(1) });
module.setData({ query: `${query}`.substring(1) });
});
messagePubSub.subscribe('scrollParent', ({ value }) => {
if (module.getData('iframePosition')?.top) {
const val = window.scrollY + value;
window.scrollTo({
top: Math.min(val, module.getData('iframePosition').top),
behavior: 'auto',
});
}
});
messagePubSub.subscribe('sdkInit', ({ value }) => {
const fallbackMode = value?.defaultThemeMode || THEME_MODE.DEFAULT;
const iframePosition = getIframePosition();
if (iframePosition?.top > IFRAME_MAX_OFFSET) {
module.setData({iframePosition});
handleScroll();
window.addEventListener('scroll', (e) => {
handleScroll();
});
}
module.emit({ href: window.location.href }, 'client-url');
setThemeMode(currentThemeMode || fallbackMode);
emitThemeMode();
});
const module = {
init: ({
languages,
prefix = 'sports',
blacklistedRoutes,
isNavigationCaptureDisabled = false,
}) => {
configuration.languages = languages;
configuration.urlPrefix = prefix;
configuration.blacklistedRoutes =
configuration.blacklistedRoutes || blacklistedRoutes;
configuration.isNavigationCaptureDisabled = isNavigationCaptureDisabled;
return module;
},
mount,
on: (event, callback) => {
const { unsubscribe } = messagePubSub.subscribe(event, callback);
return {
off: unsubscribe,
};
},
emit: (data, type) => {
postMessage(data, type);
},
helpers: {
logout: () => module.emit({ logout: true }),
toggleThemeMode,
emitThemeName,
getCurrentThemeMode: () => currentThemeMode,
updateCurrency: (currency) => module.emit({ currency }, 'currency-update'),
},
setData: (data) => {
Object.entries(data).forEach(([key, value]) => {
module.store[key] = value;
});
},
getData: (dataName) => module.store[dataName],
store: {},
};
export default module;