(function () { const INSERT_POSITION = 'beforeend'; const HIDDEN_CLASS = 'hidden'; const insertHTML = (html, target, position = INSERT_POSITION) => { target.insertAdjacentHTML(position, html); }; const padNumber = (value) => String(value).length === 1 ? `0${value}` : value; // Конфигурации для разных типов баннеров const BANNER_CONFIGS = { corner: { url: '/cst-banner', storagePrefix: 'ipBannerStateId-', className: 'ip-banner', itemClassName: 'ip-banner-item', hideTime: 600000, // 10 минут maxClicks: 3, isFullscreen: false }, fullscreen: { url: '/cst-banner-full', storagePrefix: 'ipBannerFullStateId-', className: 'ip-banner-full', itemClassName: 'ip-banner-full-item', hideTime: 21600000, // 6 часов maxClicks: 1, isFullscreen: true } }; class Banner { #originalHTML = null; #bannerElement = null; #countdownTime = null; #bannerContainer = null; #closeButton = null; #contentContainer = null; #contentFrame = null; #bannerItem = null; #countdownElement = null; #timerInterval = null; #bannerId = null; #imageElements = null; #storage = localStorage; #config = null; constructor(bannerContent, config) { this.#originalHTML = bannerContent.outerHTML; this.#bannerContainer = document.querySelector('.gc-main-content'); this.#config = config; } get templateStyle() { if (this.#config.isFullscreen) { return ` `; } else { return ` `; } } get template() { const containerClass = this.#config.isFullscreen ? 'ip-banner-full__container' : ''; const contentClass = this.#config.isFullscreen ? 'ip-banner-full__content' : 'ip-banner__content'; const closeClass = this.#config.isFullscreen ? 'ip-banner-full__close' : 'ip-banner__close'; return `
${this.#originalHTML}
`; } get element() { if (!this.#bannerElement) { this.#bannerElement = this.template; } return this.#bannerElement; } init() { // Insert banner styles and HTML insertHTML(this.templateStyle, this.#bannerContainer); insertHTML(this.element, this.#bannerContainer); // Show first banner item this.#showFirstBannerItem(); // Get banner elements this.#bannerContainer = document.querySelector(`.${this.#config.className}`); const closeSelector = this.#config.isFullscreen ? '.ip-banner-full__close' : '.ip-banner__close'; const contentSelector = this.#config.isFullscreen ? '.ip-banner-full__content' : '.ip-banner__content'; this.#closeButton = this.#bannerContainer.querySelector(closeSelector); this.#contentContainer = this.#bannerContainer.querySelector(contentSelector); this.#contentFrame = this.#contentContainer.querySelector('.lite-page.block-set'); // Modify content frame classes const frameClass = this.#config.isFullscreen ? 'ip-banner-full__content-frame' : 'ip-banner__content-frame'; this.#contentFrame.classList.add(frameClass); this.#contentFrame.classList.remove('lite-page'); this.#contentFrame.classList.remove('block-set'); // Get banner item and images this.#bannerItem = this.#bannerContainer.querySelector(`.${this.#config.itemClassName}`); this.#imageElements = this.#bannerContainer.querySelectorAll('.image-box img'); if (this.#bannerItem) { this.#countdownElement = this.#bannerItem.querySelector('.countdown-el'); this.#countdownTime = this.#countdownElement?.dataset.time; this.#bannerId = this.#bannerItem.className.split(`${this.#config.itemClassName}-`)[1]; if (this.#countdownElement) { this.#startCountdown(this.#countdownTime); } } else { this.#bannerContainer.classList.add(HIDDEN_CLASS); } // Load lazy images if (this.#imageElements.length) { for (const image of this.#imageElements) { image.src = image.dataset.src; } } // Add event listeners this.#closeButton.addEventListener('click', this.#handleCloseClick); if (this.#config.isFullscreen) { this.#bannerContainer.addEventListener('click', this.#handleBackgroundClick); document.addEventListener('keydown', this.#handleKeyPress); } } #showFirstBannerItem() { const bannerItems = document.querySelectorAll(`.${this.#config.itemClassName}`); if (bannerItems.length) { for (const item of bannerItems) { item.style = 'display: none !important'; } bannerItems[0].style = 'display: block !important'; } } #startCountdown(endTime) { if (!endTime) return; const [date, time] = endTime.split(' '); const endDateTime = moment(`${date}T${time}:00Z`); const now = moment(new Date()); let timeLeft = endDateTime.valueOf() - now.valueOf(); const intervalMs = 1000; const countdownDisplay = document.querySelector(`.${this.#config.itemClassName}-${this.#bannerId} .countdown-el`); setInterval(() => { timeLeft = moment.duration(timeLeft - intervalMs, 'milliseconds'); countdownDisplay.textContent = timeLeft - intervalMs > 0 ? `${padNumber(timeLeft.days())}Д : ${padNumber(timeLeft.hours())}Ч : ${padNumber(timeLeft.minutes())}М : ${padNumber(timeLeft.seconds())}С` : '00Д : 00Ч : 00М : 00С'; }, intervalMs); } #handleCloseClick = () => { this.#bannerContainer.classList.add(HIDDEN_CLASS); this.#saveBannerState(); if (this.#config.isFullscreen) { document.removeEventListener('keydown', this.#handleKeyPress); } }; #handleBackgroundClick = (event) => { if (event.target.classList.contains(this.#config.className)) { this.#bannerContainer.classList.add(HIDDEN_CLASS); this.#saveBannerState(); document.removeEventListener('keydown', this.#handleKeyPress); } }; #handleKeyPress = (event) => { if (event.key === 'Escape') { this.#bannerContainer.classList.add(HIDDEN_CLASS); this.#saveBannerState(); document.removeEventListener('keydown', this.#handleKeyPress); } }; #saveBannerState = () => { const bannerId = this.#bannerId; if (bannerId >= 1) { const currentTime = moment(new Date()); const storageKey = `${this.#config.storagePrefix}${bannerId}`; const storedState = this.#storage.getItem(storageKey); let clickCount = 0; if (storedState) { try { clickCount = JSON.parse(storedState).count || 0; } catch (error) { clickCount = 0; } } this.#storage.setItem( storageKey, JSON.stringify({ id: bannerId, count: clickCount + 1, timeCloseClick: currentTime }) ); } }; } // Функция для получения всех ID баннеров из localStorage const getAllBannerIdsFromStorage = (storagePrefix) => { const keys = Object.keys(localStorage); const bannerKeys = keys.filter(key => key.startsWith(storagePrefix)); return bannerKeys.map(key => parseInt(key.replace(storagePrefix, ''))); }; // Функция для проверки, нужно ли показывать баннер const shouldShowBannerByStorage = (config) => { const bannerIds = getAllBannerIdsFromStorage(config.storagePrefix); if (bannerIds.length === 0) { console.log(`${config.className}: No saved state, showing banner`); return true; // Нет сохраненного состояния - показываем баннер } // Проверяем все сохраненные баннеры for (const bannerId of bannerIds) { const storedState = localStorage.getItem(`${config.storagePrefix}${bannerId}`); if (!storedState) { continue; } try { const parsedState = JSON.parse(storedState); const clickCount = parsedState.count || 0; const timeCloseClick = moment(parsedState.timeCloseClick); const currentTime = moment(new Date()); const timeDiff = currentTime.valueOf() - timeCloseClick.valueOf(); console.log(`${config.className} ID ${bannerId}:`, { clickCount, timeDiff, hideTime: config.hideTime, maxClicks: config.maxClicks, shouldShow: timeDiff >= config.hideTime && clickCount < config.maxClicks }); // Если хотя бы один баннер должен быть показан if (timeDiff >= config.hideTime && clickCount < config.maxClicks) { return true; } } catch (error) { console.log(`Error parsing banner state for ID ${bannerId}:`, error); return true; } } console.log(`${config.className}: All banners are hidden`); return false; }; // Check if current page should show banner const shouldShowBanner = () => { const currentPath = location.pathname; const allowedPaths = [ '/teach/control/stream', '/pl/teach/control/lesson', '/sales/control', '/profile', '/src-main', '/src-library/cases', '/cst-banner-manipulator' ]; return allowedPaths.some(path => currentPath.indexOf(path) !== -1); }; const bannerDeleted = localStorage.getItem('DeleteCSTBanner'); const isShow = shouldShowBanner(); console.log('Banner script started:', { isShow, bannerDeleted, path: location.pathname }); if (isShow && !bannerDeleted) { // Загружаем оба баннера ['corner', 'fullscreen'].forEach(bannerType => { const config = BANNER_CONFIGS[bannerType]; // Проверяем, нужно ли делать запрос const shouldFetch = shouldShowBannerByStorage(config); console.log(`Should fetch ${bannerType} banner:`, shouldFetch); if (shouldFetch) { console.log(`Fetching ${bannerType} banner...`); fetch(config.url) .then(response => response.text()) .then(html => { return new DOMParser() .parseFromString(html, 'text/html') .querySelector('.lite-page.block-set'); }) .then(bannerContent => { if (bannerContent) { new Banner(bannerContent, config).init(); } }) .catch(error => console.log(`Failed to fetch ${bannerType} banner: `, error)); } else { console.log(`${bannerType} banner is hidden, skipping fetch request`); } }); } })();