Решаем вместе
Сложности с получением «Пушкинской карты» или приобретением билетов? Знаете, как улучшить работу учреждений культуры? Напишите — решим!
(function () {
'use strict';
const scriptEl = document.currentScript || document.scripts[document.scripts.length - 1];
const scriptSrcUrl = new URL(scriptEl.src);
const scriptUrl = (scriptSrcUrl.origin + scriptSrcUrl.pathname)
.split('iframe/')[0]
.replace(/\/$/, ''); // Отсекаем урл слева от iframe [корректный урл для получения ресурсов]
const src = scriptEl.src;
const url = new URL(src);
const scriptPath = url.pathname;
const scriptDir = scriptPath.substring(0, scriptPath.lastIndexOf('/'));
const ASSETS_CONFIG_HOST = 'https://gu-st.ru';
const ASSETS_CDN_HOST = ASSETS_CONFIG_HOST.startsWith('#{') ? scriptUrl : ASSETS_CONFIG_HOST;
function validatePosition(position) {
const validPositions = [
'bottom-right',
'bottom-left',
'top-right',
'top-left',
'middle-left',
'middle-right'
];
return validPositions.includes(position) ? position : 'bottom-right';
}
function getScriptParams() {
try {
const params = new URLSearchParams(url.search);
let cssFileName;
const jsFileName = scriptPath.substring(scriptPath.lastIndexOf('/') + 1);
if (jsFileName === 'boot.js') {
cssFileName = 'widget-styles.css';
} else {
cssFileName = jsFileName.replace('.js', '.css');
}
const defaultCssUrl = `${ASSETS_CDN_HOST}${scriptDir}/${cssFileName}`;
const defaultRobotImageUrl = `${ASSETS_CDN_HOST}${scriptDir}/iframe-widget.png`;
const defaultMiniRobotImageUrl = `${ASSETS_CDN_HOST}${scriptDir}/iframe-mini-widget.png`;
return {
position: validatePosition(params.get('position') || 'bottom-right'),
platform: params.get('platform') || '',
region: params.get('region') || '',
cssUrl: params.get('cssUrl') || defaultCssUrl,
robotImageUrl: params.get('robotImageUrl') || defaultRobotImageUrl,
miniRobotImageUrl: params.get('miniRobotImageUrl') || defaultMiniRobotImageUrl,
saveState: params.get('saveState') !== 'false',
initialState: params.get('initialState') === 'collapsed' ? 'collapsed' : 'expanded'
};
} catch (error) {
console.error('Ошибка парсинга параметров скрипта:', error);
return {
position: 'bottom-right',
platform: '',
cssUrl: 'widget-styles.css',
robotImageUrl: 'iframe-widget.png',
miniRobotImageUrl: 'iframe-mini-widget.png',
saveState: true,
initialState: 'expanded'
};
}
}
const scriptParams = getScriptParams();
const BOOT_CONFIG_HOST = 'https://max.gosuslugi.ru/robot-max';
const BOOT_CDN_HOST = BOOT_CONFIG_HOST.startsWith('#{') ? scriptUrl : BOOT_CONFIG_HOST;
const VERSION_CONFIG_HOST = 'https://max.gosuslugi.ru';
const VERSION_CDN_HOST = VERSION_CONFIG_HOST.startsWith('#{') ? scriptUrl : VERSION_CONFIG_HOST;
const CONFIG = {
BASE_URL: `${BOOT_CDN_HOST}/iframe`,
VERSION_ENDPOINT: `${VERSION_CDN_HOST}/iframe/version/`,
FALLBACK_VERSION: '1.0.0',
TOGGLE_ICON_URL: scriptParams.miniRobotImageUrl,
ROBOT_GREETING_IMG: scriptParams.robotImageUrl,
ALLOWED_ORIGINS: [`${BOOT_CDN_HOST}`],
CSS_LINK_ID: 'rm-widget-css-link',
IFRAME_ID: 'rm-widget-iframe',
TOGGLE_BTN_ID: 'rm-widget-toggle',
GREETING_WIDGET_ID: 'rm-greeting-widget',
POSITION: scriptParams.position,
PLATFORM: scriptParams.platform,
REGION: scriptParams.region,
CSS_URL: scriptParams.cssUrl,
SAVE_STATE: scriptParams.saveState,
INITIAL_STATE: scriptParams.initialState,
MOBILE_BREAKPOINT: 768,
BUTTON_MARGINS: {
mobile: 16,
mobileBottom: 24,
desktop: 30
},
BUTTON_HEIGHT: 90,
DRAG_THRESHOLD: 5,
SWIPE_THRESHOLD: 50,
MAX_ANGLE_HORIZONTAL: 30
};
async function initWidget() {
function initKeyboardDetection() {
let lastHeight = window.innerHeight;
let lastWidth = window.innerWidth;
let keyboardVisible = false;
let resizeTimeout;
const KEYBOARD_THRESHOLD = 150;
function detectKeyboard() {
const currentHeight = window.innerHeight;
const currentWidth = window.innerWidth;
const heightDiff = lastHeight - currentHeight;
const widthChanged = Math.abs(lastWidth - currentWidth) > 10;
if (!widthChanged && heightDiff > KEYBOARD_THRESHOLD && !keyboardVisible) {
keyboardVisible = true;
sendKeyboardEvent(true, currentHeight, heightDiff);
} else if (!widthChanged && heightDiff < -KEYBOARD_THRESHOLD && keyboardVisible) {
keyboardVisible = false;
sendKeyboardEvent(false, currentHeight, Math.abs(heightDiff));
}
lastHeight = currentHeight;
lastWidth = currentWidth;
}
function sendKeyboardEvent(isVisible, viewportHeight, keyboardHeight) {
if (iframe && iframe.contentWindow) {
iframe.contentWindow.postMessage({
type: 'keyboard-visibility-change',
data: {
isVisible: isVisible,
viewportHeight: viewportHeight,
keyboardHeight: keyboardHeight,
timestamp: Date.now()
}
}, CONFIG.BASE_URL);
}
}
window.addEventListener('resize', () => {
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(detectKeyboard, 100);
});
if ('visualViewport' in window) {
window.visualViewport.addEventListener('resize', () => {
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(() => {
const heightDiff = window.innerHeight - window.visualViewport.height;
if (heightDiff > 50 && !keyboardVisible) {
keyboardVisible = true;
sendKeyboardEvent(true, window.visualViewport.height, heightDiff);
} else if (heightDiff < 50 && keyboardVisible) {
keyboardVisible = false;
sendKeyboardEvent(false, window.visualViewport.height, 0);
}
}, 100);
});
}
}
function getPositionStyles(position) {
const margin = `${CONFIG.BUTTON_MARGINS.desktop}px`;
const widgetPosition = {
bottom: margin,
};
const widgetMobilePosition = {
bottom: `${CONFIG.BUTTON_MARGINS.mobileBottom}px`,
transform: 'none'
};
const positions = {
'bottom-right': {
widget: widgetPosition,
widgetMobile: widgetMobilePosition,
widgetHidden: { transform: 'translateX(50%) translateY(20px)' },
widgetHiddenMobile: { transform: 'translateY(20px)' },
button: { bottom: margin, right: margin },
buttonMobile: { right: `${CONFIG.BUTTON_MARGINS.mobile}px` },
isLeft: false
},
'bottom-left': {
widget: widgetPosition,
widgetMobile: widgetMobilePosition,
widgetHidden: { transform: 'translateX(50%) translateY(20px)' },
widgetHiddenMobile: { transform: 'translateY(20px)' },
button: { bottom: margin, left: margin },
buttonMobile: { left: `${CONFIG.BUTTON_MARGINS.mobile}px` },
isLeft: true
},
'top-right': {
widget: widgetPosition,
widgetMobile: widgetMobilePosition,
widgetHidden: { transform: 'translateX(50%) translateY(20px)' },
widgetHiddenMobile: { transform: 'translateY(20px)' },
button: { top: margin, right: margin },
buttonMobile: { right: `${CONFIG.BUTTON_MARGINS.mobile}px` },
isLeft: false
},
'top-left': {
widget: widgetPosition,
widgetMobile: widgetMobilePosition,
widgetHidden: { transform: 'translateX(50%) translateY(20px)' },
widgetHiddenMobile: { transform: 'translateY(20px)' },
button: { top: margin, left: margin },
buttonMobile: { left: `${CONFIG.BUTTON_MARGINS.mobile}px` },
isLeft: true
},
'middle-left': {
widget: widgetPosition,
widgetMobile: widgetMobilePosition,
widgetHidden: { transform: 'translateX(50%) translateY(20px)' },
widgetHiddenMobile: { transform: 'translateY(20px)' },
button: { top: '50%', left: margin, transform: 'translateY(-50%)' },
buttonMobile: {
left: `${CONFIG.BUTTON_MARGINS.mobile}px`,
top: '50%',
transform: 'translateY(-50%)'
},
isLeft: true
},
'middle-right': {
widget: widgetPosition,
widgetMobile: widgetMobilePosition,
widgetHidden: { transform: 'translateX(50%) translateY(20px)' },
widgetHiddenMobile: { transform: 'translateY(20px)' },
button: { top: '50%', right: margin, transform: 'translateY(-50%)' },
buttonMobile: {
right: `${CONFIG.BUTTON_MARGINS.mobile}px`,
top: '50%',
transform: 'translateY(-50%)'
},
isLeft: false
}
};
return positions[position] || positions['bottom-right'];
}
function injectCSS() {
if (!document.getElementById(CONFIG.CSS_LINK_ID)) {
const link = document.createElement('link');
link.id = CONFIG.CSS_LINK_ID;
link.rel = 'stylesheet';
link.href = CONFIG.CSS_URL;
link.onerror = () => {
console.error('Ошибка загрузки CSS файла виджета:', CONFIG.CSS_URL);
};
document.head.appendChild(link);
}
}
function injectFontFaces() {
if (document.getElementById('rm-widget-fonts')) return;
const fontStyles = document.createElement('style');
fontStyles.id = 'rm-widget-fonts';
fontStyles.textContent = `
@font-face {
font-family: 'Lato';
src: url('${ASSETS_CDN_HOST}${scriptDir}/fonts/Lato-Regular-v2.woff2') format('woff2'),
url('${ASSETS_CDN_HOST}${scriptDir}/fonts/Lato-Regular-v2.woff') format('woff');
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Lato';
src: url('${ASSETS_CDN_HOST}${scriptDir}/fonts/Lato-Bold-v2.woff2') format('woff2'),
url('${ASSETS_CDN_HOST}${scriptDir}/fonts/Lato-Bold-v2.woff') format('woff');
font-weight: 700;
font-style: normal;
font-display: swap;
}
`;
document.head.appendChild(fontStyles);
}
injectFontFaces();
injectCSS();
function createIframe() {
const iframe = document.createElement('iframe');
iframe.id = CONFIG.IFRAME_ID;
iframe.setAttribute('loading', 'lazy');
return iframe;
}
function createImg(src, alt) {
const img = document.createElement('img');
img.src = src;
img.alt = alt;
img.addEventListener('error', () => (img.style.display = 'none'));
return img;
}
function createBtn(iconImg) {
const btn = document.createElement('button');
btn.id = CONFIG.TOGGLE_BTN_ID;
btn.type = 'button';
btn.setAttribute('aria-label', 'Открыть виджет');
if (iconImg) btn.appendChild(iconImg);
return btn;
}
function createGreetingWidget() {
const container = document.createElement('div');
container.id = CONFIG.GREETING_WIDGET_ID;
container.className = 'greeting-widget';
container.innerHTML = `
`;
return container;
}
function appendToBody(...elements) {
elements.forEach(el => document.body.appendChild(el));
}
const iframe = createIframe();
const btn = createBtn(createImg(CONFIG.TOGGLE_ICON_URL, 'РРєРѕРЅРєР° виджета'));
const greetingWidget = createGreetingWidget();
appendToBody(iframe, btn, greetingWidget);
initKeyboardDetection();
function isMobile() {
return window.innerWidth <= CONFIG.MOBILE_BREAKPOINT;
}
function resetButtonPosition() {
['top', 'bottom', 'left', 'right', 'transform'].forEach(prop => {
btn.style[prop] = '';
greetingWidget.style[prop] = '';
});
}
function applyIconFlip(isLeft) {
const img = btn.querySelector('img');
if (img) {
img.style.transform = isLeft ? 'scaleX(-1)' : '';
}
}
function applyPositioning(position = CONFIG.POSITION, targetBtn = btn, targetWidget = greetingWidget) {
const positionStyles = getPositionStyles(position);
resetButtonPosition(targetBtn, targetWidget);
targetWidget.setAttribute('data-position', position);
Object.entries(positionStyles.widget).forEach(([prop, value]) => {
targetWidget.style[prop] = value;
});
Object.entries(positionStyles.button).forEach(([prop, value]) => {
targetBtn.style[prop] = value;
});
targetWidget.dataset.hiddenTransform = positionStyles.widgetHidden.transform;
applyIconFlip(positionStyles.isLeft);
if (isMobile()) {
Object.entries(positionStyles.widgetMobile).forEach(([prop, value]) => {
targetWidget.style[prop] = value;
});
Object.entries(positionStyles.buttonMobile).forEach(([prop, value]) => {
targetBtn.style[prop] = value;
});
targetWidget.dataset.hiddenTransformMobile = positionStyles.widgetHiddenMobile.transform;
}
}
function resetButtonPositionFor(targetBtn, targetWidget) {
['top', 'bottom', 'left', 'right', 'transform'].forEach(prop => {
targetBtn.style[prop] = '';
targetWidget.style[prop] = '';
});
}
applyPositioning();
function saveButtonPosition(y) {
if (CONFIG.SAVE_STATE) {
localStorage.setItem('rm-widget-button-y', y.toString());
}
}
function loadButtonPosition() {
if (!CONFIG.SAVE_STATE) return null;
const savedY = localStorage.getItem('rm-widget-button-y');
return savedY ? parseFloat(savedY) : null;
}
function saveButtonSide(isLeft) {
if (CONFIG.SAVE_STATE) {
localStorage.setItem('rm-widget-button-side', isLeft ? 'left' : 'right');
}
}
function loadButtonSide() {
if (!CONFIG.SAVE_STATE) return null;
return localStorage.getItem('rm-widget-button-side');
}
function setButtonY(y) {
const viewportHeight = window.innerHeight;
const buttonHeight = CONFIG.BUTTON_HEIGHT;
const minY = CONFIG.BUTTON_MARGINS.mobileBottom;
const maxY = viewportHeight - buttonHeight - CONFIG.BUTTON_MARGINS.mobileBottom;
const clampedY = Math.max(minY, Math.min(maxY, y));
if (isMobile()) {
btn.style.top = `${clampedY}px`;
btn.style.bottom = 'auto';
}
}
function setButtonHorizontalPosition(isLeft) {
if (isMobile()) {
const margin = `${CONFIG.BUTTON_MARGINS.mobile}px`;
if (isLeft) {
btn.style.left = margin;
btn.style.right = 'auto';
} else {
btn.style.right = margin;
btn.style.left = 'auto';
}
applyIconFlip(isLeft);
}
}
function initButtonPosition() {
if (isMobile()) {
const savedY = loadButtonPosition();
if (savedY !== null) {
setButtonY(savedY);
} else {
const defaultY =
CONFIG.POSITION.startsWith('top-') || CONFIG.POSITION.startsWith('middle-')
? CONFIG.BUTTON_MARGINS.mobileBottom
: window.innerHeight - CONFIG.BUTTON_HEIGHT - CONFIG.BUTTON_MARGINS.mobileBottom;
setButtonY(defaultY);
}
const savedSide = loadButtonSide();
const isLeft = savedSide ? savedSide === 'left' : CONFIG.POSITION.includes('left');
setButtonHorizontalPosition(isLeft);
}
}
function getButtonCenter(useAskButton = false) {
if (useAskButton) {
const askBtn = greetingWidget.querySelector('.rm-widget-btn.main');
if (askBtn) {
const rect = askBtn.getBoundingClientRect();
return {
x: rect.left + rect.width / 2,
y: rect.top + rect.height / 2
};
}
}
const rect = btn.getBoundingClientRect();
if (btn.classList.contains('show') && rect.width > 0 && rect.height > 0) {
return {
x: rect.left + rect.width / 2,
y: rect.top + rect.height / 2
};
}
const isMobileView = isMobile();
const buttonSize = isMobileView ? 80 : 76;
const halfSize = buttonSize / 2;
let x, y;
if (isMobileView) {
if (btn.style.left && btn.style.left !== 'auto') {
x = parseFloat(btn.style.left) + halfSize;
} else if (btn.style.right && btn.style.right !== 'auto') {
x = window.innerWidth - parseFloat(btn.style.right) - halfSize;
} else {
if (CONFIG.POSITION.includes('left')) {
x = CONFIG.BUTTON_MARGINS.mobile + halfSize;
} else {
x = window.innerWidth - CONFIG.BUTTON_MARGINS.mobile - halfSize;
}
}
if (btn.style.top && btn.style.top !== 'auto') {
y = parseFloat(btn.style.top) + halfSize;
} else if (btn.style.bottom && btn.style.bottom !== 'auto') {
y = window.innerHeight - parseFloat(btn.style.bottom) - halfSize;
} else {
if (CONFIG.POSITION.includes('top')) {
y = CONFIG.BUTTON_MARGINS.mobile + halfSize;
} else if (CONFIG.POSITION.includes('middle')) {
y = window.innerHeight / 2;
} else {
y = window.innerHeight - CONFIG.BUTTON_MARGINS.mobileBottom - halfSize;
}
}
} else {
const position = CONFIG.POSITION;
if (position.includes('left')) {
x = CONFIG.BUTTON_MARGINS.desktop + halfSize;
} else {
x = window.innerWidth - CONFIG.BUTTON_MARGINS.desktop - halfSize;
}
if (position.includes('top')) {
y = CONFIG.BUTTON_MARGINS.desktop + halfSize;
} else if (position.includes('middle')) {
y = window.innerHeight / 2;
} else {
y = window.innerHeight - CONFIG.BUTTON_MARGINS.desktop - halfSize;
}
}
return { x, y };
}
function setTransformOrigin(element, buttonCenter) {
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
const originX = (buttonCenter.x / viewportWidth) * 100;
const originY = (buttonCenter.y / viewportHeight) * 100;
element.style.setProperty('--origin-x', `${originX}%`);
element.style.setProperty('--origin-y', `${originY}%`);
element.style.transformOrigin = `${originX}% ${originY}%`;
}
function initToggleButton(targetBtn) {
const dragThreshold = CONFIG.DRAG_THRESHOLD;
const swipeThreshold = CONFIG.SWIPE_THRESHOLD;
const maxAngleForHorizontalSwipe = CONFIG.MAX_ANGLE_HORIZONTAL;
let isDragging = false;
let startX = 0;
let startY = 0;
let startButtonY = 0;
let hasMoved = false;
let isHorizontalSwipe = false;
let isVerticalDrag = false;
function handleStart(e) {
if (!isMobile()) return;
isDragging = true;
hasMoved = false;
isHorizontalSwipe = false;
isVerticalDrag = false;
targetBtn.classList.add('dragging');
const clientX = e.type === 'touchstart' ? e.touches[0].clientX : e.clientX;
const clientY = e.type === 'touchstart' ? e.touches[0].clientY : e.clientY;
startX = clientX;
startY = clientY;
const currentTop =
parseInt(targetBtn.style.top) ||
(CONFIG.POSITION.startsWith('top-') || CONFIG.POSITION.startsWith('middle-')
? CONFIG.BUTTON_MARGINS.mobileBottom
: window.innerHeight - CONFIG.BUTTON_HEIGHT - CONFIG.BUTTON_MARGINS.mobileBottom);
startButtonY = currentTop;
}
function handleMove(e) {
if (!isDragging || !isMobile()) return;
const clientX = e.type === 'touchmove' ? e.touches[0].clientX : e.clientX;
const clientY = e.type === 'touchmove' ? e.touches[0].clientY : e.clientY;
const deltaX = clientX - startX;
const deltaY = clientY - startY;
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance > dragThreshold && !hasMoved) {
hasMoved = true;
const angle = Math.abs((Math.atan2(deltaY, deltaX) * 180) / Math.PI);
const isHorizontal =
angle <= maxAngleForHorizontalSwipe || angle >= 180 - maxAngleForHorizontalSwipe;
if (isHorizontal && Math.abs(deltaX) > Math.abs(deltaY)) {
isHorizontalSwipe = true;
isVerticalDrag = false;
} else {
isVerticalDrag = true;
isHorizontalSwipe = false;
}
}
if (hasMoved && isVerticalDrag) {
const newY = startButtonY + deltaY;
setButtonY(newY);
e.preventDefault();
} else if (hasMoved && isHorizontalSwipe) {
e.preventDefault();
}
if (hasMoved) {
e.preventDefault();
}
}
function handleEnd(e) {
if (!isDragging || !isMobile()) return;
isDragging = false;
targetBtn.classList.remove('dragging');
if (hasMoved) {
const clientX = e.type === 'touchend' ? e.changedTouches[0].clientX : e.clientX;
const deltaX = clientX - startX;
if (isHorizontalSwipe && Math.abs(deltaX) >= swipeThreshold) {
targetBtn.classList.add('swipe-animating');
const isLeft = deltaX < 0;
setButtonHorizontalPosition(isLeft);
saveButtonSide(isLeft);
setTimeout(() => {
targetBtn.classList.remove('swipe-animating');
}, 200);
e.preventDefault();
e.stopPropagation();
} else if (isVerticalDrag) {
const currentY = parseInt(targetBtn.style.top) || startButtonY;
saveButtonPosition(currentY);
e.preventDefault();
e.stopPropagation();
}
}
}
targetBtn.addEventListener('mousedown', handleStart);
targetBtn.addEventListener('touchstart', handleStart, { passive: false });
document.addEventListener('mousemove', handleMove);
document.addEventListener('touchmove', handleMove, { passive: false });
document.addEventListener('mouseup', handleEnd);
document.addEventListener('touchend', handleEnd);
targetBtn.addEventListener('click', e => {
if (hasMoved) {
e.preventDefault();
e.stopPropagation();
return;
}
openIframe();
});
}
initToggleButton(btn);
let resizeTimer;
window.addEventListener('resize', () => {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => {
applyPositioning(CONFIG.POSITION, btn, greetingWidget);
if (isMobile()) {
initButtonPosition();
} else {
resetButtonPosition();
applyPositioning(CONFIG.POSITION, btn, greetingWidget);
}
}, 100);
});
function buildIframeUrl(baseUrl) {
try {
const url = new URL(baseUrl);
const fullUrl = window.location.href;
url.searchParams.set('link', fullUrl);
if (CONFIG.PLATFORM && CONFIG.PLATFORM.trim() !== '') {
url.searchParams.set('platform', CONFIG.PLATFORM.trim());
}
if (CONFIG.REGION && CONFIG.REGION.trim() !== '') {
url.searchParams.set('region', CONFIG.REGION.trim());
}
return url.toString();
} catch (error) {
console.error('Ошибка построения URL для iframe:', error);
return baseUrl;
}
}
async function fetchVersionedUrl() {
try {
const ctrl = new AbortController();
const timer = setTimeout(() => ctrl.abort(), 5000);
const res = await fetch(CONFIG.VERSION_ENDPOINT, {
signal: ctrl.signal,
method: 'GET',
headers: {
Accept: 'application/json',
'Cache-Control': 'no-cache'
}
});
clearTimeout(timer);
if (!res.ok) {
throw new Error(`HTTP ${res.status}: ${res.statusText}`);
}
const json = await res.json();
if (!json || typeof json.v !== 'string') {
throw new Error('Некорректный формат ответа');
}
const version = json.v.replace(/[^0-9.]/g, '') || CONFIG.FALLBACK_VERSION;
const baseUrl = `${CONFIG.BASE_URL}/${version}/`;
return buildIframeUrl(baseUrl);
} catch (error) {
if (error.name === 'AbortError') {
console.error('Запрос версии прерван по тайм-ауту');
} else {
console.error('Ошибка загрузки версии:', error.message);
}
const fallbackUrl = `${CONFIG.BASE_URL}/${CONFIG.FALLBACK_VERSION}/`;
return buildIframeUrl(fallbackUrl);
}
}
fetchVersionedUrl().then(url => (iframe.src = url));
function showToggleButton() {
btn.classList.add('show');
if (isMobile()) {
initButtonPosition();
}
}
function hideToggleButton() {
btn.classList.remove('show');
}
function hideGreetingWidget() {
if (CONFIG.SAVE_STATE) {
localStorage.setItem('rm-widget-greeting-hidden', 'true');
}
btn.style.opacity = '0';
btn.style.pointerEvents = 'none';
btn.classList.add('show');
if (isMobile()) {
initButtonPosition();
}
requestAnimationFrame(() => {
const buttonCenter = getButtonCenter();
setTransformOrigin(greetingWidget, buttonCenter);
greetingWidget.classList.add('hiding');
setTimeout(() => {
greetingWidget.classList.add('hidden');
greetingWidget.classList.remove('hiding');
btn.style.opacity = '';
btn.style.pointerEvents = '';
}, 400);
});
}
function openIframe() {
const useAskButton = !greetingWidget.classList.contains('hidden');
const wasHidden = !btn.classList.contains('show') && greetingWidget.classList.contains('hidden');
if (wasHidden) {
btn.style.opacity = '0';
btn.style.pointerEvents = 'none';
btn.classList.add('show');
if (isMobile()) {
initButtonPosition();
}
}
requestAnimationFrame(() => {
const buttonCenter = getButtonCenter(useAskButton);
setTransformOrigin(iframe, buttonCenter);
if (wasHidden) {
btn.classList.remove('show');
btn.style.opacity = '';
btn.style.pointerEvents = '';
}
iframe.classList.add('opening');
iframe.classList.add('open');
greetingWidget.classList.add('hidden');
greetingWidget.classList.remove('appearing');
hideToggleButton();
document.body.style.overflow = 'hidden';
setTimeout(() => {
iframe.classList.remove('opening');
}, 480);
});
iframe.classList.add('open');
greetingWidget.classList.add('hidden');
hideToggleButton();
document.body.style.overflow = 'hidden';
iframe.contentWindow.postMessage('openIframe', '*');
}
function closeIframe() {
const currentY = isMobile() ? parseInt(btn.style.top) : null;
btn.style.opacity = '0';
btn.style.pointerEvents = 'none';
btn.classList.add('show');
if (isMobile()) {
initButtonPosition();
}
requestAnimationFrame(() => {
const buttonCenter = getButtonCenter();
setTransformOrigin(iframe, buttonCenter);
iframe.classList.add('closing');
setTimeout(() => {
iframe.classList.remove('open');
iframe.classList.remove('closing');
btn.style.opacity = '';
btn.style.pointerEvents = '';
if (isMobile() && currentY !== null) {
btn.style.top = `${currentY}px`;
}
document.body.style.overflow = '';
}, 480);
});
}
function initGreetingWidget(widgetEl) {
const askBtn = widgetEl.querySelector('.rm-widget-btn.main');
const notNowBtn = widgetEl.querySelector('.rm-widget-btn:not(.main)');
const closeBtn = widgetEl.querySelector('.rm-widget-close');
if (askBtn) askBtn.addEventListener('click', openIframe);
if (notNowBtn) notNowBtn.addEventListener('click', hideGreetingWidget);
if (closeBtn) closeBtn.addEventListener('click', hideGreetingWidget);
}
initGreetingWidget(greetingWidget);
if (CONFIG.SAVE_STATE && localStorage.getItem('rm-widget-greeting-hidden') === 'true') {
greetingWidget.classList.add('hidden');
showToggleButton();
} else {
if (CONFIG.INITIAL_STATE === 'collapsed') {
greetingWidget.classList.add('hidden');
showToggleButton();
}
}
window.addEventListener('message', e => {
if (e.data === 'closeIframe') {
closeIframe();
}
});
document.addEventListener('keydown', e => {
if (e.key === 'Escape') {
if (iframe.classList.contains('open')) {
closeIframe();
} else if (!greetingWidget.classList.contains('hidden')) {
hideGreetingWidget();
}
}
});
}
if (document.readyState === 'complete') {
initWidget().catch();
} else {
window.addEventListener('load', () => initWidget().catch(console.error));
}
})();