(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`);
}
});
}
})();