/* GETCOURSE — USER TRAINING INSIDE / v0.4.6 */
(function () {
'use strict';
const ROUTE_RE = /^\/teach\/control\/stream\/view\/id\/\d+\/?$/;
const FETCH_CACHE = new Map();
const SUPPORT_URL =
'/pl/talks/conversation';
function isTargetPage() {
return ROUTE_RE.test(window.location.pathname);
}
function isLearnerView() {
/*
 * Менеджеры и преподаватели могут открывать тренинг как обычный
 * пользователь. Пользовательскую оболочку не запускаем только
 * для полноценного администратора, чтобы не конфликтовать с
 * отдельной admin-кастомизацией тренинга.
 */
return window.userInfo?.isAdmin !== true;
}
if (!isTargetPage() || !isLearnerView()) return;
document.documentElement.classList.add(
'pt-user-inside-loading'
);
const guard = document.createElement('style');
guard.id = 'pt-user-inside-fouc';
guard.textContent = `
html.pt-user-inside-loading
body .main-page-block > .container {
visibility: hidden !important;
opacity: 0 !important;
}
`;
document.head.appendChild(guard);
const cleanText = (value) =>
String(value || '')
.replace(/\s+/g, ' ')
.trim();
function getTrainingType() {
return cleanText(
document.querySelector(
'.psych-training-type[data-training-type]'
)?.getAttribute(
'data-training-type'
)
).toLowerCase();
}
function isFreeWebinarsTraining() {
return (
getTrainingType() ===
'free-webinars'
);
}
function getTrainingSettings() {
const marker =
document.querySelector(
'.psych-training-settings'
);
return {
scheduleUrl:
cleanText(
marker?.getAttribute(
'data-schedule-url'
)
)
};
}
function getLessonRows(root = document) {
return Array.from(
root.querySelectorAll(
'.xdget-lessonList .lesson-list > li[data-lesson-id]'
)
);
}
function getSectionRows(root = document) {
return Array.from(
root.querySelectorAll(
'.xdget-trainingList .stream-table .training-row'
)
);
}
function getLessonTitle(row) {
const source = row.querySelector('.link.title');
if (!source) return '';
const clone = source.cloneNode(true);
clone.querySelectorAll(
'.lesson-list__video-watched'
).forEach(el => el.remove());
return cleanText(clone.textContent);
}
function getLessonDescription(row) {
return cleanText(
row.querySelector('.description')?.textContent
);
}
function getLessonStatusText(row) {
return cleanText(
row.querySelector('.user-state-label')?.textContent
);
}
function getLessonState(row) {
const native =
getLessonStatusText(row);
if (
/(?:не\s*принят|не\s*зачт|отклон)/i
.test(native)
) {
return 'declined';
}
if (row.classList.contains('user-state-accomplished')) {
return 'done';
}
if (row.classList.contains('user-state-answered')) {
return 'answered';
}
if (row.classList.contains('user-state-not_reached')) {
return 'locked';
}
return 'available';
}
function getLessonHref(row) {
return row.querySelector(
':scope > a.item-a[href]'
)?.href || '';
}
function getLessonImage(row) {
const imageCell = row.querySelector('.item-image');
if (!imageCell) return '';
const raw =
imageCell.style.backgroundImage ||
window.getComputedStyle(imageCell).backgroundImage ||
'';
const match = raw.match(/url\(["']?(.*?)["']?\)/);
return match?.[1] || '';
}
function padNumber(index) {
return String(index + 1).padStart(2, '0');
}
function stateLabel(row) {
const state = getLessonState(row);
const native = getLessonStatusText(row);
if (state === 'done') return 'Пройден';
if (state === 'answered') return 'Ответ отправлен';
if (state === 'declined') {
return native || 'Задание не принято';
}
if (native) {
return native
.replace('Необходимо выполнить задание', 'Стоп-урок')
.replace(/\s*\(стоп-урок\)\s*/i, '')
.trim() || 'Стоп-урок';
}
if (state === 'locked') return 'Недоступен';
return 'Доступен';
}
function decorateFreeWebinarRows() {
const rows = getLessonRows();
rows.forEach((row, index) => {
if (
row.classList.contains(
'ps-webinar-ready'
)
) return;
row.classList.add(
'ps-webinar-ready'
);
row.dataset.psychState =
getLessonState(row);
const item =
row.querySelector(
':scope > .item-a'
);
const info =
row.querySelector('.info');
if (!item || !info) return;
const title =
getLessonTitle(row);
const description =
getLessonDescription(row);
const imageUrl =
getLessonImage(row);
const watched =
row.classList.contains(
'user-state-accomplished'
) ||
Boolean(
row.querySelector(
'.lesson-list__video-watched'
)
);
row.querySelectorAll(
'.lesson-list__video-watched'
).forEach(el => {
el.style.display = 'none';
});
const cover =
document.createElement('span');
cover.className =
'ps-webinar-cover';
if (imageUrl) {
const img =
document.createElement('img');
img.src = imageUrl;
img.alt = '';
cover.appendChild(img);
} else {
cover.classList.add(
'ps-webinar-cover--empty'
);
}
const play =
document.createElement('span');
play.className =
'ps-webinar-play';
play.setAttribute(
'aria-hidden',
'true'
);
play.innerHTML = `
<svg viewBox="0 0 24 24"
fill="none">
<circle cx="12" cy="12" r="10"
fill="currentColor"/>
<path d="m10 8.75 5.5 3.25-5.5 3.25v-6.5Z"
fill="white"/>
</svg>
`;
cover.appendChild(play);
const body =
document.createElement('span');
body.className =
'ps-webinar-body';
const eyebrow =
document.createElement('span');
eyebrow.className =
'ps-webinar-eyebrow';
eyebrow.textContent =
watched
? 'Просмотрено'
: 'Запись вебинара';
const heading =
document.createElement('strong');
heading.className =
'ps-webinar-title';
heading.textContent =
title || `Вебинар ${index + 1}`;
body.append(
eyebrow,
heading
);
if (description) {
const text =
document.createElement('span');
text.className =
'ps-webinar-description';
text.textContent =
description;
body.appendChild(text);
}
item.innerHTML = '';
item.append(
cover,
body
);
row.querySelectorAll(
'.state-icon-block, .item-image'
).forEach(el => {
el.classList.add(
'ps-native-hidden'
);
});
});
}
function decorateLessonRows() {
const rows = getLessonRows();
rows.forEach((row, index) => {
if (row.classList.contains(
'ps-lesson-ready'
)) return;
row.classList.add(
'ps-lesson-ready'
);
row.dataset.psychState =
getLessonState(row);
const item = row.querySelector(
':scope > .item-a'
);
const info = row.querySelector('.info');
if (!item || !info) return;
row.querySelectorAll(
'.lesson-list__video-watched'
).forEach(el => {
el.style.display = 'none';
});
const imageUrl = getLessonImage(row);
const marker = document.createElement('span');
marker.className = 'ps-lesson-marker';
if (imageUrl) {
marker.classList.add(
'ps-lesson-marker--image'
);
const img = document.createElement('img');
img.src = imageUrl;
img.alt = '';
marker.appendChild(img);
} else {
marker.textContent = padNumber(index);
}
item.insertBefore(marker, info);
const badge = document.createElement('span');
badge.className = 'ps-lesson-badge';
badge.textContent = stateLabel(row);
badge.dataset.state = getLessonState(row);
const arrow = document.createElement('span');
arrow.className = 'ps-lesson-arrow';
arrow.setAttribute('aria-hidden', 'true');
arrow.textContent = '→';
item.appendChild(badge);
item.appendChild(arrow);
row.querySelectorAll(
'.state-icon-block, .item-image'
).forEach(el => {
el.classList.add('ps-native-hidden');
});
});
}
function decorateSections() {
const rows = getSectionRows();
rows.forEach(row => {
if (row.classList.contains(
'ps-section-ready'
)) return;
const link = row.querySelector('td > a[href]');
const title = row.querySelector('.stream-title');
if (!link || !title) return;
row.classList.add(
'ps-section-ready'
);
const titleText =
cleanText(title.textContent);
const meta =
cleanText(
link.querySelector('div')?.textContent
);
const imageUrl =
cleanText(
row.getAttribute('data-training-image')
);
link.className =
'ps-section-card';
link.innerHTML = '';
const marker = document.createElement('span');
marker.className =
'ps-section-marker';
if (imageUrl) {
const img =
document.createElement('img');
img.src = imageUrl;
img.alt = '';
marker.appendChild(img);
marker.classList.add(
'ps-section-marker--image'
);
} else {
marker.innerHTML = `
<svg viewBox="0 0 24 24"
width="20"
height="20"
aria-hidden="true">
<path d="M4 5.5A1.5 1.5 0 0 1 5.5 4H10l2 2h6.5A1.5 1.5 0 0 1 20 7.5v9A1.5 1.5 0 0 1 18.5 18h-13A1.5 1.5 0 0 1 4 16.5v-11Z"
fill="none"
stroke="currentColor"
stroke-width="1.7"
stroke-linejoin="round"/>
</svg>
`;
}
const content =
document.createElement('span');
content.className =
'ps-section-content';
const eyebrow =
document.createElement('span');
eyebrow.className =
'ps-section-eyebrow';
eyebrow.textContent =
'Раздел программы';
const heading =
document.createElement('span');
heading.className =
'ps-section-title';
heading.textContent = titleText;
const details =
document.createElement('span');
details.className =
'ps-section-meta';
details.textContent =
meta || 'Открыть раздел';
const arrow =
document.createElement('span');
arrow.className =
'ps-section-arrow';
arrow.textContent = '→';
content.append(
eyebrow,
heading,
details
);
link.append(
marker,
content,
arrow
);
});
}
function getChatSources() {
const markers =
Array.from(
document.querySelectorAll(
'.psych-training-chat-source'
)
);
return markers
.map(marker => {
const link =
marker.querySelector(
'a[href]'
);
if (!link) {
return null;
}
const href =
cleanText(
link.getAttribute('href')
);
if (!href) {
return null;
}
const match =
href.match(
/\/c\/(\d+)(?:[/?#]|$)/
);
const block =
marker.closest(
'.xdget-block'
);
if (block) {
block.classList.add(
'ps-chat-source-block'
);
}
return {
id:
match?.[1] || '',
title:
cleanText(
link.textContent
) || 'Чат программы',
href
};
})
.filter(Boolean);
}
function iconChat() {
return `
<svg viewBox="0 0 24 24"
fill="none"
aria-hidden="true">
<path d="M5 5.5h14a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-7l-4.5 3v-3H5a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2Z"
stroke="currentColor"
stroke-width="1.7"
stroke-linejoin="round"/>
</svg>
`;
}
function iconSupport() {
return `
<svg viewBox="0 0 24 24"
fill="none"
aria-hidden="true">
<path d="M4 13v-1a8 8 0 0 1 16 0v1"
stroke="currentColor"
stroke-width="1.7"
stroke-linecap="round"/>
<path d="M4 13.5a2.5 2.5 0 0 1 2.5-2.5H8v6H6.5A2.5 2.5 0 0 1 4 14.5v-1Zm16 0a2.5 2.5 0 0 0-2.5-2.5H16v6h1.5a2.5 2.5 0 0 0 2.5-2.5v-1Z"
stroke="currentColor"
stroke-width="1.7"/>
<path d="M17 17.5c-.5 1.5-1.8 2.5-4 2.5"
stroke="currentColor"
stroke-width="1.7"
stroke-linecap="round"/>
</svg>
`;
}
function iconCalendar() {
return `
<svg viewBox="0 0 24 24"
fill="none"
aria-hidden="true">
<rect x="4" y="5.5"
width="16"
height="14"
rx="2"
stroke="currentColor"
stroke-width="1.7"/>
<path d="M8 3.5v4M16 3.5v4M4 9.5h16"
stroke="currentColor"
stroke-width="1.7"
stroke-linecap="round"/>
</svg>
`;
}
function buildServiceAction(
title,
description,
href,
icon,
external = false
) {
const link =
document.createElement('a');
link.className =
'ps-service-action';
link.href = href;
if (external) {
link.target = '_blank';
link.rel = 'noopener';
}
const iconBox =
document.createElement('span');
iconBox.className =
'ps-service-icon';
iconBox.innerHTML = icon;
const content =
document.createElement('span');
content.className =
'ps-service-content';
const heading =
document.createElement('strong');
heading.textContent = title;
const text =
document.createElement('span');
text.textContent = description;
content.append(
heading,
text
);
const arrow =
document.createElement('span');
arrow.className =
'ps-service-arrow';
arrow.textContent = '→';
link.append(
iconBox,
content,
arrow
);
return link;
}
function buildServices() {
if (
document.querySelector(
'.ps-services'
)
) return;
const anchor =
document.querySelector(
'.ps-continue'
) ||
document.querySelector(
'.ps-hero'
);
if (!anchor) return;
const chats =
getChatSources();
const section =
document.createElement('section');
section.className =
'ps-services';
const heading =
document.createElement('div');
heading.className =
'ps-services__heading';
heading.innerHTML = `
<h2>Полезное для обучения</h2>
<p>Помощь и общение</p>
`;
const grid =
document.createElement('div');
grid.className =
'ps-services__grid';
if (chats.length === 1) {
const chat = chats[0];
const link =
buildServiceAction(
'Чат программы',
'Общайтесь с группой и кураторами',
chat.href,
iconChat()
);
link.classList.add(
'ps-chat-single'
);
if (chat.id) {
link.dataset.chatId =
chat.id;
}
const badge =
document.createElement('span');
badge.className =
'ps-chat-unread';
badge.hidden = true;
link.insertBefore(
badge,
link.querySelector(
'.ps-service-arrow'
)
);
grid.appendChild(
link
);
} else if (chats.length > 1) {
const chatCard =
document.createElement('div');
chatCard.className =
'ps-chat-card';
const chatHead =
document.createElement('div');
chatHead.className =
'ps-chat-card__head';
const chatIcon =
document.createElement('span');
chatIcon.className =
'ps-service-icon';
chatIcon.innerHTML =
iconChat();
const chatHeadText =
document.createElement('div');
const chatTitle =
document.createElement('strong');
chatTitle.textContent =
'Чаты программы';
const chatDescription =
document.createElement('span');
chatDescription.textContent =
'Доступные вам чаты';
chatHeadText.append(
chatTitle,
chatDescription
);
chatHead.append(
chatIcon,
chatHeadText
);
const list =
document.createElement('div');
list.className =
'ps-chat-list';
chats.forEach(chat => {
const link =
document.createElement('a');
link.className =
'ps-chat-link';
link.href =
chat.href;
if (chat.id) {
link.dataset.chatId =
chat.id;
}
const title =
document.createElement('span');
title.className =
'ps-chat-link__title';
title.textContent =
chat.title;
const badge =
document.createElement('span');
badge.className =
'ps-chat-unread';
badge.hidden = true;
const arrow =
document.createElement('span');
arrow.className =
'ps-chat-link__arrow';
arrow.textContent = '→';
link.append(
title,
badge,
arrow
);
list.appendChild(link);
});
chatCard.append(
chatHead,
list
);
grid.appendChild(
chatCard
);
}
grid.appendChild(
buildServiceAction(
'Поддержка',
'Задать вопрос в тех.поддержку',
SUPPORT_URL,
iconSupport()
)
);
const {
scheduleUrl
} =
getTrainingSettings();
if (scheduleUrl) {
grid.appendChild(
buildServiceAction(
'Расписание',
'Вебинары и встречи',
scheduleUrl,
iconCalendar(),
true
)
);
}
if (!chats.length) {
grid.classList.add(
'ps-services__grid--without-chat'
);
}
section.append(
heading,
grid
);
anchor.insertAdjacentElement(
'afterend',
section
);
refreshChatUnread(
chats
);
}

function buildTutorCard() {
if (document.querySelector('.ps-tutor-section')) return;

const tutors =
Array.from(document.querySelectorAll('.tutor'))
.filter(el => {
const style = window.getComputedStyle(el);
return (
style.display !== 'none' &&
style.visibility !== 'hidden' &&
el.querySelector('img')
);
});

if (!tutors.length) return;

const source = tutors[0];
const image =
source.querySelector('.img-assistant img, img');

const nameBlocks =
Array.from(
source.querySelectorAll('.xdget-html .html-content')
).filter(el => !el.closest('.img-assistant'));

const name =
cleanText(
nameBlocks
.map(el => el.textContent)
.find(Boolean) || ''
);

if (!image || !name) return;

const section = document.createElement('section');
section.className = 'ps-tutor-section';

const heading = document.createElement('div');
heading.className = 'ps-tutor-section__heading';
heading.innerHTML = `
<h2>Ваш куратор</h2>
<p>Сопровождает Вас на курсе</p>
`;

const card = document.createElement('div');
card.className = 'ps-tutor-card';

const avatar = document.createElement('div');
avatar.className = 'ps-tutor-card__avatar';

const img = document.createElement('img');
img.src = image.currentSrc || image.src;
img.alt = name;
img.loading = 'lazy';
avatar.appendChild(img);

const content = document.createElement('div');
content.className = 'ps-tutor-card__content';

const role = document.createElement('span');
role.className = 'ps-tutor-card__role';
role.textContent = 'Куратор';

const title = document.createElement('strong');
title.className = 'ps-tutor-card__name';
title.textContent = name;

const text = document.createElement('span');
text.className = 'ps-tutor-card__text';

const isNoFeedbackTutor =
name === 'Дина Турбовская';

text.textContent =
isNoFeedbackTutor
? 'Проверяет выполнение заданий и сопровождает прохождение курса без индивидуальной обратной связи'
: 'Даст обратную связь по ответам и поможет с возникающими вопросами';

content.append(role, title, text);

const icon = document.createElement('span');
icon.className = 'ps-tutor-card__icon';
icon.setAttribute('aria-hidden', 'true');
icon.innerHTML = `
<svg viewBox="0 0 24 24" fill="none">
<path d="M12 13.25a4.25 4.25 0 1 0 0-8.5 4.25 4.25 0 0 0 0 8.5Z"
stroke="currentColor" stroke-width="1.7"/>
<path d="M4.75 20c.72-3.22 3.42-5.25 7.25-5.25S18.28 16.78 19.25 20"
stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/>
</svg>
`;

card.append(avatar, content, icon);
section.append(heading, card);

const services =
document.querySelector('.ps-services');

if (services) {
services.insertAdjacentElement(
'beforebegin',
section
);
} else {
const anchor =
document.querySelector('.ps-continue') ||
document.querySelector('.ps-hero');

if (!anchor) return;

anchor.insertAdjacentElement(
'afterend',
section
);
}

/* Исходные блоки остаются источником данных и сегментации GetCourse. */
document
.querySelectorAll('.tutor')
.forEach(el => el.classList.add('ps-native-tutor'));

const nativeTitle =
Array.from(
document.querySelectorAll('#manual-title .html-content')
).find(el =>
/ваш\s+куратор/i.test(cleanText(el.textContent))
);

nativeTitle
?.closest('.xdget-block')
?.classList.add('ps-native-tutor-title');
}

async function refreshChatUnread(chats) {
const ids =
chats
.map(chat => chat.id)
.filter(Boolean);
if (!ids.length) return;
try {
const fd =
new FormData();
ids.forEach(id => {
fd.append(
'courseIds[]',
id
);
});
const response =
await fetch(
'/pl/c/unread-by-courses',
{
method: 'POST',
body: fd,
credentials: 'same-origin'
}
);
if (!response.ok) return;
const result =
await response.json();
const counts =
result?.data?.counts;
if (
!result?.success ||
!counts
) return;
ids.forEach(id => {
const badge =
document.querySelector(
`[data-chat-id="${id}"] .ps-chat-unread`
);
if (!badge) return;
const value =
counts[id];
if (
value &&
Number(value) > 0
) {
badge.textContent =
Number(value) > 99
? '99+'
: String(value);
badge.hidden = false;
} else {
badge.hidden = true;
}
});
} catch (error) {
}
}
function buildContentHeading() {
if (
document.querySelector(
'.ps-content-heading'
)
) return;
const firstBlock =
document.querySelector(
'.xdget-training .xdget-lessonList, ' +
'.xdget-training .xdget-trainingList'
);
if (!firstBlock) return;
const heading =
document.createElement('div');
heading.className =
'ps-content-heading';
heading.innerHTML =
isFreeWebinarsTraining()
? `
<h2>Записи вебинаров</h2>
<p>Выберите запись и смотрите в удобном темпе</p>
`
: `
<h2>Содержание программы</h2>
<p>Продвигайтесь по материалам в удобном темпе</p>
`;
firstBlock.parentNode.insertBefore(
heading,
firstBlock
);
}
function makeSingleColumn() {
const training =
document.querySelector('.xdget-training');
if (!training) return;
training.classList.add(
'ps-training-root'
);
const row =
training.querySelector(':scope > .xdget-row');
if (!row) return;
const cols =
Array.from(
row.children
).filter(el =>
el.classList.contains('xdget-container')
);
if (!cols.length) return;
cols[0].classList.add(
'ps-main-column'
);
cols.slice(1).forEach(col => {
const meaningful =
col.querySelector(
'.xdget-lessonList, ' +
'.xdget-trainingList, ' +
'.xdget-trainingChats, ' +
'.xdget-trainingAchievements'
);
if (!meaningful || !cleanText(col.textContent)) {
col.classList.add(
'ps-side-column-empty'
);
}
});
}
function parseDocument(html) {
return new DOMParser().parseFromString(
html,
'text/html'
);
}
async function fetchDoc(url) {
const absolute =
new URL(url, window.location.origin).href;
if (FETCH_CACHE.has(absolute)) {
return FETCH_CACHE.get(absolute);
}
const promise =
fetch(absolute, {
credentials: 'same-origin'
})
.then(response => {
if (!response.ok) {
throw new Error(
`HTTP ${response.status}`
);
}
return response.text();
})
.then(parseDocument);
FETCH_CACHE.set(absolute, promise);
return promise;
}
function summarizeLessons(root) {
const rows = getLessonRows(root);
let total = rows.length;
let done = 0;
let next = null;
for (const row of rows) {
const state = getLessonState(row);
if (state === 'done') {
done += 1;
}
if (
!next &&
state !== 'done' &&
state !== 'answered'
) {
const href = getLessonHref(row);
if (href) {
next = {
href,
title: getLessonTitle(row),
description:
getLessonDescription(row)
};
}
}
}
return {
total,
done,
next
};
}
async function summarizeTraining(
root,
visited = new Set()
) {
const current =
summarizeLessons(root);
let total = current.total;
let done = current.done;
let next = current.next;
const sections =
getSectionRows(root);
for (const section of sections) {
const href =
section.querySelector(
'td > a[href]'
)?.href;
if (!href) continue;
const absolute =
new URL(
href,
window.location.origin
).href;
if (visited.has(absolute)) continue;
visited.add(absolute);
try {
const doc =
await fetchDoc(absolute);
const nested =
await summarizeTraining(
doc,
visited
);
total += nested.total;
done += nested.done;
if (!next && nested.next) {
next = nested.next;
}
} catch (error) {
console.warn(
'[training-user-inside] ' +
'Не удалось посчитать вложенный раздел:',
error
);
}
}
return {
total,
done,
next
};
}
function getTrainingTitle() {
return cleanText(
document.querySelector(
'.page-header h1'
)?.textContent
);
}
function getTrainingDescription() {
return cleanText(
document.querySelector(
'.training-hidden-data'
)?.dataset.description
);
}
function getTrainingImage() {
return cleanText(
document.querySelector(
'.training-hidden-data'
)?.dataset.trainingImage
);
}
function buildHero(summary) {
if (
document.querySelector(
'.ps-hero'
)
) return;
const header =
document.querySelector('.page-header');
if (!header) return;
const title = getTrainingTitle();
const description =
getTrainingDescription();
const image =
getTrainingImage();
const freeWebinars =
isFreeWebinarsTraining();
const percent =
summary.total
? Math.round(
summary.done /
summary.total *
100
)
: 0;
const hero =
document.createElement('section');
hero.className =
'ps-hero';
if (image) {
hero.classList.add(
'ps-hero--with-image'
);
}
hero.innerHTML = `
${image ? `
<div class="ps-hero__image">
<img src="${image}" alt="">
</div>
` : ''}
<div class="ps-hero__body">
<h1>${title}</h1>
${description ? `
<p class="ps-hero__description">
${description}
</p>
` : ''}
${freeWebinars ? `
<div class="ps-webinar-hero-meta">
<span class="ps-webinar-hero-badge">
Бесплатные вебинары
</span>
<span class="ps-webinar-hero-count">
${summary.total === 1
? '1 запись'
: `${summary.total} записей`}
</span>
</div>
` : `
<div class="ps-progress">
<div class="ps-progress__meta">
<span>
${summary.done} из ${summary.total} уроков
</span>
<strong>${percent}%</strong>
</div>
<div class="ps-progress__track">
<span style="width:${percent}%"></span>
</div>
</div>
`}
</div>
`;
header.insertAdjacentElement(
'afterend',
hero
);
header.classList.add(
'ps-native-header'
);
}
function buildContinue(summary) {
if (!summary.next) return;
if (
document.querySelector(
'.ps-continue'
)
) return;
const hero =
document.querySelector(
'.ps-hero'
);
if (!hero) return;
const card =
document.createElement('a');
card.className =
'ps-continue';
card.href =
summary.next.href;
card.innerHTML = `
<span class="ps-continue__icon">
&#9654;
</span>
<span class="ps-continue__content">
<span class="ps-continue__eyebrow">
Продолжить обучение
</span>
<strong>
${summary.next.title || 'Следующий урок'}
</strong>
${summary.next.description ? `
<span class="ps-continue__description">
${summary.next.description}
</span>
` : ''}
</span>
<span class="ps-continue__action">
Продолжить
<span>→</span>
</span>
`;
hero.insertAdjacentElement(
'afterend',
card
);
}
function decorateBreadcrumbs() {
const native =
document.querySelector(
'.main-page-block > .container > .breadcrumbs'
);
if (
!native ||
document.querySelector(
'.ps-breadcrumbs'
)
) return;
native.classList.add(
'ps-native-breadcrumbs'
);
const custom =
document.createElement('nav');
custom.className =
'ps-breadcrumbs';
const links =
Array.from(
native.querySelectorAll('a[href]')
);
links.forEach((link, index) => {
const clone =
link.cloneNode(true);
if (
cleanText(clone.textContent) ===
'Тренинги'
) {
clone.textContent =
'Мои тренинги';
}
custom.appendChild(clone);
if (index < links.length - 1) {
const sep =
document.createElement('span');
sep.textContent = '›';
custom.appendChild(sep);
}
});
native.parentNode.insertBefore(
custom,
native
);
}
function release() {
document.documentElement.classList.add(
'pt-user-inside-ready'
);
document.body.classList.add(
'pt-user-inside-ready'
);
requestAnimationFrame(() => {
requestAnimationFrame(() => {
document.documentElement.classList.remove(
'pt-user-inside-loading'
);
document.getElementById(
'pt-user-inside-fouc'
)?.remove();
});
});
}
async function init() {
try {
decorateBreadcrumbs();
const freeWebinars =
isFreeWebinarsTraining();
if (!freeWebinars) {
getChatSources();
}
makeSingleColumn();
if (freeWebinars) {
document.documentElement.classList.add(
'ps-free-webinars'
);
document.body.classList.add(
'ps-free-webinars'
);
decorateFreeWebinarRows();
} else {
decorateLessonRows();
}
decorateSections();
buildContentHeading();
const summary =
await summarizeTraining(
document,
new Set([
window.location.href
])
);
buildHero(summary);
if (!freeWebinars) {
buildContinue(summary);
buildServices();
buildTutorCard();
}
window.setTimeout(() => {
if (!freeWebinars) {
getChatSources();
}
makeSingleColumn();
if (freeWebinars) {
decorateFreeWebinarRows();
} else {
decorateLessonRows();
}
decorateSections();
buildContentHeading();
if (!freeWebinars) {
buildServices();
buildTutorCard();
}
}, 250);
document.addEventListener(
'visibilitychange',
() => {
if (
document.visibilityState ===
'visible' &&
!freeWebinars
) {
refreshChatUnread(
getChatSources()
);
}
}
);
window.addEventListener(
'pageshow',
() => {
if (!freeWebinars) {
refreshChatUnread(
getChatSources()
);
}
}
);
} catch (error) {
console.error(
'[training-user-inside]',
error
);
} finally {
release();
}
}
if (
document.readyState === 'loading'
) {
document.addEventListener(
'DOMContentLoaded',
init,
{ once: true }
);
} else {
init();
}
})();