add: добавлена кнопка "скопировать в буфер обмена" и отслеживание целей в Yandex-Metrica и Top-Mail.ru
All checks were successful
Build ETPGRF-site / build (push) Successful in 1m26s
All checks were successful
Build ETPGRF-site / build (push) Successful in 1m26s
This commit is contained in:
@@ -1,115 +1,133 @@
|
||||
(function () {
|
||||
const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
const logoImg = document.getElementById('logo-img');
|
||||
const navbar = document.getElementById('main-navbar');
|
||||
"use strict";
|
||||
|
||||
// --- АВТОМАТИЧЕСКОЕ ПЕРЕКЛЮЧЕНИЕ ТЕМЫ (Dark/Light) ---
|
||||
function updateTheme(e) {
|
||||
const theme = e.matches ? 'dark' : 'light';
|
||||
document.documentElement.setAttribute('data-bs-theme', theme);
|
||||
}
|
||||
// --- АВТОМАТИЧЕСКОЕ ПЕРЕКЛЮЧЕНИЕ ТЕМЫ (Dark/Light) ---
|
||||
const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
|
||||
// --- ОБНОВЛЕНИЕ ЛОГОТИПА ПРИ СКРОЛЛЕ И СМЕНЕ ТЕМЫ ---
|
||||
function updateLogo() {
|
||||
const isDark = darkModeMediaQuery.matches;
|
||||
// Используем getBoundingClientRect для определения позиции контента
|
||||
if (document.getElementById('content-container').getBoundingClientRect().top < 78) {
|
||||
navbar.classList.add('navbar-scrolled');
|
||||
logoImg.src = isDark ? logoImg.dataset.srcDarkCompact : logoImg.dataset.srcLightCompact;
|
||||
} else {
|
||||
navbar.classList.remove('navbar-scrolled');
|
||||
logoImg.src = isDark ? logoImg.dataset.srcDark : logoImg.dataset.srcLight;
|
||||
function updateTheme(e) {
|
||||
const theme = e.matches ? 'dark' : 'light';
|
||||
document.documentElement.setAttribute('data-bs-theme', theme);
|
||||
// При смене темы обновляем и логотип
|
||||
updateLogo();
|
||||
}
|
||||
}
|
||||
|
||||
// Инициализация
|
||||
updateTheme(darkModeMediaQuery);
|
||||
updateLogo();
|
||||
document.addEventListener('DOMContentLoaded', updateLogo);
|
||||
// --- ЛОГОТИП И СКРОЛЛ ---
|
||||
function updateLogo() {
|
||||
const logoImg = document.getElementById('logo-img');
|
||||
const navbar = document.getElementById('main-navbar');
|
||||
|
||||
if (!logoImg || !navbar) return;
|
||||
|
||||
// Слушаем скролл
|
||||
window.addEventListener('scroll', updateLogo);
|
||||
const isDark = darkModeMediaQuery.matches;
|
||||
// Используем window.scrollY для определения прокрутки
|
||||
// Если прокрутили больше 50px, уменьшаем шапку
|
||||
const isScrolled = window.scrollY > 50;
|
||||
|
||||
// Слушаем смену темы
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', updateLogo);
|
||||
if (isScrolled) {
|
||||
navbar.classList.add('navbar-scrolled');
|
||||
logoImg.src = isDark ? logoImg.dataset.srcDarkCompact : logoImg.dataset.srcLightCompact;
|
||||
} else {
|
||||
navbar.classList.remove('navbar-scrolled');
|
||||
logoImg.src = isDark ? logoImg.dataset.srcDark : logoImg.dataset.srcLight;
|
||||
}
|
||||
}
|
||||
|
||||
// --- КУКИ ---
|
||||
const COOKIE_KEY = 'cookie_consent';
|
||||
const TTL_MS = 90 * 24 * 60 * 60 * 1000; // 90 дней: 90 * 24 * 60 * 60 * 1000 = 7776000000)
|
||||
// Инициализация темы и логотипа
|
||||
updateTheme(darkModeMediaQuery);
|
||||
darkModeMediaQuery.addEventListener('change', updateTheme);
|
||||
|
||||
// Инициализация логотипа при загрузке и скролле
|
||||
document.addEventListener('DOMContentLoaded', updateLogo);
|
||||
window.addEventListener('scroll', updateLogo);
|
||||
|
||||
const banner = document.getElementById('cookie-banner');
|
||||
const acceptButton = document.getElementById('cookie-accept');
|
||||
|
||||
// Функция загрузки счетчиков аналитики
|
||||
function loadCounters() {
|
||||
// console.log("Загрузка счетчиков (Яндекс, Google)...");
|
||||
// Код Яндекс.Метрики
|
||||
(function (m, e, t, r, i, k, a) {
|
||||
m[i] = m[i] || function () { (m[i].a = m[i].a || []).push(arguments) };
|
||||
m[i].l = 1 * new Date();
|
||||
for (var j = 0; j < document.scripts.length; j++) { if (document.scripts[j].src === r) { return; } }
|
||||
k = e.createElement(t), a = e.getElementsByTagName(t)[0], k.async = 1, k.src = r, a.parentNode.insertBefore(k, a)
|
||||
})(window, document, 'script', 'https://mc.yandex.ru/metrika/tag.js?id=106310834', 'ym');
|
||||
ym(106310834, 'init', {
|
||||
ssr: true, webvisor: true, clickmap: true, ecommerce: "dataLayer",
|
||||
accurateTrackBounce: true, trackLinks: true
|
||||
// --- КУКИ И СЧЕТЧИКИ ---
|
||||
const COOKIE_KEY = 'cookie_consent';
|
||||
const TTL_MS = 90 * 24 * 60 * 60 * 1000; // 90 дней
|
||||
const MAILRU_ID = "3734603";
|
||||
const YANDEX_ID = "106310834";
|
||||
|
||||
function loadCounters() {
|
||||
// console.log("Загрузка счетчиков...");
|
||||
try {
|
||||
// Mail.ru
|
||||
var _tmr = window._tmr || (window._tmr = []);
|
||||
_tmr.push({id: MAILRU_ID, type: "pageView", start: (new Date()).getTime()});
|
||||
(function (d, w, id) {
|
||||
if (d.getElementById(id)) return;
|
||||
var ts = d.createElement("script"); ts.type = "text/javascript"; ts.async = true; ts.id = id;
|
||||
ts.src = "https://top-fwz1.mail.ru/js/code.js";
|
||||
var f = d.getElementsByTagName("script")[0]; f.parentNode.insertBefore(ts, f);
|
||||
})(document, window, "topmailru-code");
|
||||
|
||||
// Яндекс.Метрика
|
||||
(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
|
||||
m[i].l=1*new Date();
|
||||
for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }}
|
||||
k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
|
||||
(window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");
|
||||
|
||||
window.ym(YANDEX_ID, "init", {
|
||||
clickmap:true,
|
||||
trackLinks:true,
|
||||
accurateTrackBounce:true
|
||||
});
|
||||
} catch (e) {
|
||||
console.error("Ошибка загрузки счетчиков:", e);
|
||||
}
|
||||
}
|
||||
|
||||
function checkConsent() {
|
||||
try {
|
||||
const stored = localStorage.getItem(COOKIE_KEY);
|
||||
if (!stored) return false;
|
||||
const data = JSON.parse(stored);
|
||||
const now = Date.now();
|
||||
if (now - data.timestamp > TTL_MS) {
|
||||
localStorage.removeItem(COOKIE_KEY);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Инициализация куки-баннера
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const banner = document.getElementById('cookie-banner');
|
||||
const acceptButton = document.getElementById('cookie-accept');
|
||||
|
||||
if (banner && acceptButton) {
|
||||
if (checkConsent()) {
|
||||
loadCounters();
|
||||
} else {
|
||||
banner.style.display = 'block';
|
||||
}
|
||||
|
||||
acceptButton.addEventListener('click', function () {
|
||||
const data = { value: true, timestamp: Date.now() };
|
||||
localStorage.setItem(COOKIE_KEY, JSON.stringify(data));
|
||||
banner.style.display = 'none';
|
||||
loadCounters();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Код Google Analytics
|
||||
// window.dataLayer = window.dataLayer || [];
|
||||
// function gtag(){dataLayer.push(arguments);}
|
||||
// gtag('js', new Date());
|
||||
// gtag('config', 'G-XXXXXXXXXX');
|
||||
|
||||
// Код Top.Mail.Ru
|
||||
var _tmr = window._tmr || (window._tmr = []);
|
||||
_tmr.push({id: "3734603", type: "pageView", start: (new Date()).getTime()});
|
||||
(function (d, w, id) {
|
||||
if (d.getElementById(id)) return;
|
||||
var ts = d.createElement("script");
|
||||
ts.type = "text/javascript"; ts.async = true; ts.id = id; ts.src = "https://top-fwz1.mail.ru/js/code.js";
|
||||
var f = function () {
|
||||
var s = d.getElementsByTagName("script")[0]; s.parentNode.insertBefore(ts, s);
|
||||
};
|
||||
if (w.opera == "[object Opera]") {
|
||||
d.addEventListener("DOMContentLoaded", f, false);
|
||||
} else { f(); }
|
||||
})(document, window, "tmr-code");
|
||||
// <noscript><div><img src="https://top-fwz1.mail.ru/counter?id=3734603;js=na" style="position:absolute;left:-9999px;" alt="Top.Mail.Ru" /></div></noscript>
|
||||
// alert("Отладка. Счетчики загружены (здесь должен быть реальный код счетчиков).");
|
||||
}
|
||||
|
||||
function checkConsent() {
|
||||
const stored = localStorage.getItem(COOKIE_KEY);
|
||||
if (!stored) return false;
|
||||
|
||||
try {
|
||||
const data = JSON.parse(stored);
|
||||
const now = Date.now();
|
||||
// Проверяем, не истек ли срок
|
||||
if (now - data.timestamp > TTL_MS) {
|
||||
localStorage.removeItem(COOKIE_KEY);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (checkConsent()) {
|
||||
loadCounters();
|
||||
} else {
|
||||
banner.style.display = 'block';
|
||||
}
|
||||
|
||||
acceptButton.addEventListener('click', function () {
|
||||
const data = {
|
||||
value: true,
|
||||
timestamp: Date.now()
|
||||
|
||||
// Глобальная функция для отправки целей
|
||||
window.sendGoal = function(goalName) {
|
||||
if (!checkConsent()) return;
|
||||
// console.log("Sending goal:", goalName);
|
||||
|
||||
try {
|
||||
if (window._tmr) {
|
||||
window._tmr.push({ id: MAILRU_ID, type: "reachGoal", goal: goalName, value: 1 });
|
||||
}
|
||||
if (typeof window.ym === 'function') {
|
||||
window.ym(YANDEX_ID, 'reachGoal', goalName);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Ошибка отправки цели:", e);
|
||||
}
|
||||
};
|
||||
localStorage.setItem(COOKIE_KEY, JSON.stringify(data));
|
||||
banner.style.display = 'none';
|
||||
loadCounters();
|
||||
});
|
||||
})();
|
||||
})();
|
||||
|
||||
@@ -19,9 +19,12 @@ import {
|
||||
} from "../codemirror/editor.js";
|
||||
|
||||
const resultWrapper = document.getElementById('cm-result-wrapper');
|
||||
const btnCopy = document.getElementById('btn-copy');
|
||||
const sourceTextarea = document.querySelector('textarea[name="text"]');
|
||||
|
||||
// console.log("Index.js loaded. btnCopy:", !!btnCopy, "sourceTextarea:", !!sourceTextarea); // DEBUG
|
||||
|
||||
const themeCompartment = new Compartment();
|
||||
|
||||
function getTheme() {
|
||||
return window.matchMedia('(prefers-color-scheme: dark)').matches ? oneDark : [];
|
||||
}
|
||||
@@ -47,8 +50,10 @@ const charNames = {
|
||||
0x2063: "Invisible Comma (невидимая запятая для семантической разметки математических выражений — ⁣)",
|
||||
};
|
||||
|
||||
const PLACEHOLDER_TEXT = "Здесь появится результат...";
|
||||
|
||||
const resultState = EditorState.create({
|
||||
doc: "Здесь появится результат...",
|
||||
doc: PLACEHOLDER_TEXT,
|
||||
extensions: [
|
||||
lineNumbers(),
|
||||
highlightActiveLineGutter(),
|
||||
@@ -83,17 +88,77 @@ const resultView = new EditorView({
|
||||
parent: resultWrapper
|
||||
});
|
||||
|
||||
// Обработка ответа от сервера (HTMX)
|
||||
document.body.addEventListener('htmx:afterSwap', function (evt) {
|
||||
// console.log("HTMX afterSwap event:", evt.detail.target.id); // DEBUG
|
||||
if (evt.detail.target.id === 'result-area') {
|
||||
const newContent = evt.detail.xhr.response;
|
||||
|
||||
// Обновляем редактор
|
||||
resultView.dispatch({
|
||||
changes: {from: 0, to: resultView.state.doc.length, insert: newContent}
|
||||
});
|
||||
|
||||
// Показываем кнопку копирования
|
||||
if (btnCopy) {
|
||||
// console.log("Showing copy button"); // DEBUG
|
||||
btnCopy.classList.remove('d-none');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Скрываем кнопку и сбрасываем редактор при изменении исходного текста
|
||||
if (sourceTextarea) {
|
||||
sourceTextarea.addEventListener('input', () => {
|
||||
if (btnCopy) {
|
||||
btnCopy.classList.add('d-none');
|
||||
}
|
||||
// Сбрасываем редактор на плейсхолдер
|
||||
if (resultView.state.doc.toString() !== PLACEHOLDER_TEXT) {
|
||||
resultView.dispatch({
|
||||
changes: {from: 0, to: resultView.state.doc.length, insert: PLACEHOLDER_TEXT}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
|
||||
resultView.dispatch({
|
||||
effects: themeCompartment.reconfigure(getTheme())
|
||||
});
|
||||
});
|
||||
|
||||
// --- КОПИРОВАНИЕ В БУФЕР ---
|
||||
if (btnCopy) {
|
||||
btnCopy.addEventListener('click', async () => {
|
||||
const text = resultView.state.doc.toString();
|
||||
// console.log("Copying text:", text.substring(0, 20) + "..."); // DEBUG
|
||||
|
||||
// Отправляем цель в метрику
|
||||
if (typeof window.sendGoal === 'function') {
|
||||
window.sendGoal('etpgrf-copy-pressed');
|
||||
}
|
||||
|
||||
try {
|
||||
await navigator.clipboard.writeText(text);
|
||||
|
||||
// Визуальное подтверждение
|
||||
const originalHtml = btnCopy.innerHTML;
|
||||
const originalClass = btnCopy.className;
|
||||
|
||||
btnCopy.innerHTML = '<i class="bi bi-check-lg me-1"></i> Скопировано!';
|
||||
btnCopy.classList.remove('btn-outline-secondary', 'btn-outline-primary');
|
||||
btnCopy.classList.add('btn-success');
|
||||
|
||||
setTimeout(() => {
|
||||
btnCopy.innerHTML = originalHtml;
|
||||
btnCopy.className = originalClass;
|
||||
btnCopy.classList.remove('d-none');
|
||||
}, 2000);
|
||||
|
||||
} catch (err) {
|
||||
console.error('Ошибка копирования:', err);
|
||||
alert('Не удалось скопировать текст.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user