/
var
/
www
/
coeditor.org
/
users
/
test.coeditor.org
/
assets
/
js
/
/var/www/coeditor.org/users/test.coeditor.org/assets/js
mkdir
upload
Name
Size
Mode
Actions
main.js
27566
0644
edit
dl
rm
Edit:
/var/www/coeditor.org/users/test.coeditor.org/assets/js/main.js
(27566B)
console.log("Landing generated successfully"); // Hero Video Playback Modes (function() { var videos = document.querySelectorAll('.hero-video-background video'); if (!videos.length) return; function normalizeVideoMode(rawMode) { var mode = String(rawMode || '').trim().toLowerCase(); if (!mode) return 'loop'; if (mode === 'loop' || mode.indexOf('по кругу') !== -1) return 'loop'; if (mode === 'once' || mode.indexOf('один раз') !== -1) return 'once'; if (mode === 'boomerang' || mode.indexOf('бумеранг') !== -1 || mode.indexOf('вперёд-назад') !== -1) return 'boomerang'; return 'loop'; } videos.forEach(function(video) { var mode = normalizeVideoMode(video.dataset.videoPlayMode || video.getAttribute('data-video-play-mode')); video.loop = mode === 'loop'; if (mode === 'loop') return; video.removeAttribute('loop'); if (mode !== 'boomerang') return; var reverseFrameId = null; var isManualReverse = false; var reverseStarted = false; function stopManualReverse() { isManualReverse = false; if (reverseFrameId !== null) { cancelAnimationFrame(reverseFrameId); reverseFrameId = null; } } function playForwardFromStart() { stopManualReverse(); reverseStarted = false; video.loop = false; video.removeAttribute('loop'); video.playbackRate = 1; video.currentTime = 0; video.play().catch(function() {}); } function playBackwardFromEndManual() { if (isManualReverse) return; var lastTimestamp = null; var duration = video.duration || 0; stopManualReverse(); isManualReverse = true; reverseStarted = true; video.loop = false; video.removeAttribute('loop'); video.pause(); video.currentTime = Math.max(duration - 0.05, 0); function step(timestamp) { if (!isManualReverse) return; if (lastTimestamp === null) { lastTimestamp = timestamp; reverseFrameId = requestAnimationFrame(step); return; } var deltaSeconds = (timestamp - lastTimestamp) / 1000; lastTimestamp = timestamp; var nextTime = video.currentTime - deltaSeconds; if (nextTime <= 0.05) { video.currentTime = 0; playForwardFromStart(); return; } video.currentTime = nextTime; reverseFrameId = requestAnimationFrame(step); } reverseFrameId = requestAnimationFrame(step); } video.addEventListener('ended', function() { playBackwardFromEndManual(); }); video.addEventListener('timeupdate', function() { if (isManualReverse) return; video.loop = false; if (video.hasAttribute('loop')) video.removeAttribute('loop'); var duration = video.duration || 0; if (!duration) return; if (!reverseStarted && video.currentTime >= duration - 0.08) { playBackwardFromEndManual(); } if (video.currentTime < 0.2) { reverseStarted = false; } }); video.addEventListener('play', function() { if (isManualReverse) { video.pause(); } }); video.addEventListener('emptied', function() { stopManualReverse(); }); }); })(); // Dynamic JSON Form Block (function() { var forms = document.querySelectorAll('.dynamic-json-form[data-submit-url]'); if (!forms.length) return; function formDataToJson(formData) { var result = {}; formData.forEach(function(value, key) { if (Object.prototype.hasOwnProperty.call(result, key)) { if (!Array.isArray(result[key])) result[key] = [result[key]]; result[key].push(value); } else { result[key] = value; } }); return result; } forms.forEach(function(form) { var statusEl = form.querySelector('.form-submit-status'); var submitBtn = form.querySelector('button[type="submit"]'); var submitUrl = form.dataset.submitUrl; var successMessage = form.dataset.successMessage || 'Спасибо! Заявка отправлена.'; var errorMessage = form.dataset.errorMessage || 'Не удалось отправить форму. Попробуйте позже.'; var resetOnSuccess = form.dataset.resetOnSuccess !== 'false'; var isSubmitting = false; function setStatus(message, kind) { if (!statusEl) return; statusEl.textContent = message || ''; statusEl.classList.remove('is-success', 'is-error', 'is-loading'); if (kind) statusEl.classList.add(kind); } form.addEventListener('submit', async function(e) { e.preventDefault(); if (isSubmitting) return; if (!submitUrl) return; isSubmitting = true; if (submitBtn) submitBtn.disabled = true; setStatus('Отправка...', 'is-loading'); try { var payload = { formId: form.id || null, submittedAt: new Date().toISOString(), pageUrl: window.location.href, data: formDataToJson(new FormData(form)) }; var response = await fetch(submitUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify(payload) }); if (!response.ok) { throw new Error('HTTP ' + response.status); } setStatus(successMessage, 'is-success'); if (resetOnSuccess) form.reset(); } catch (_) { setStatus(errorMessage, 'is-error'); } finally { isSubmitting = false; if (submitBtn) submitBtn.disabled = false; } }); }); })(); // Sticky Header Shrink + Anchor Offset Scroll (function() { var headers = document.querySelectorAll('.block-header.header-sticky'); if (!headers.length) return; var docEl = document.documentElement; var menuToggle = document.querySelector('.mobile-menu-toggle'); var headerNav = document.querySelector('.header-nav'); var ticking = false; function currentHeader() { return headers[0] || null; } var cachedCompactHeight = null; function getAnchorOffset() { var header = currentHeader(); if (!header) return 56; if (header.classList.contains('header-scrolled')) { cachedCompactHeight = Math.ceil(header.getBoundingClientRect().height); return cachedCompactHeight + 12; } if (cachedCompactHeight !== null) return cachedCompactHeight + 12; // First-time measurement: temporarily toggle class with transitions disabled var container = header.querySelector('.container'); var items = header.querySelectorAll('.logo, .logo-image, .menu > a, .menu-item-has-children, .btn-header'); var origT = header.style.transition; var origCT = container ? container.style.transition : ''; header.style.transition = 'none'; if (container) container.style.transition = 'none'; items.forEach(function(el) { el.dataset._t = el.style.transition; el.style.transition = 'none'; }); header.classList.add('header-scrolled'); void header.offsetHeight; cachedCompactHeight = Math.ceil(header.getBoundingClientRect().height); header.classList.remove('header-scrolled'); header.style.transition = origT; if (container) container.style.transition = origCT; items.forEach(function(el) { el.style.transition = el.dataset._t || ''; delete el.dataset._t; }); void header.offsetHeight; return cachedCompactHeight + 12; } function setAnchorOffsetVar() { docEl.style.setProperty('--header-anchor-offset', getAnchorOffset() + 'px'); } function updateHeaderState() { var y = window.pageYOffset || docEl.scrollTop || 0; headers.forEach(function(header) { header.classList.toggle('header-scrolled', y > 16); }); setAnchorOffsetVar(); } function onScroll() { if (ticking) return; ticking = true; requestAnimationFrame(function() { updateHeaderState(); ticking = false; }); } function findHashTarget(hash) { if (!hash || hash.length < 2) return null; var id = decodeURIComponent(hash.slice(1)); return document.getElementById(id) || document.querySelector('[name="' + id.replace(/"/g, '\\"') + '"]'); } function scrollToHash(hash, behavior) { var target = findHashTarget(hash); if (!target) return false; // Measure target position first, then offset separately var targetTop = window.pageYOffset + target.getBoundingClientRect().top; var offset = getAnchorOffset(); var top = targetTop - offset; window.scrollTo({ top: Math.max(0, top), behavior: behavior || 'smooth' }); return true; } document.addEventListener('click', function(e) { var link = e.target.closest('a[href*="#"]'); if (!link) return; var href = link.getAttribute('href') || ''; if (href === '#' || href.indexOf('#') === -1) return; var targetUrl; try { targetUrl = new URL(link.href, window.location.href); } catch (_) { return; } if (targetUrl.origin !== window.location.origin) return; if (targetUrl.pathname !== window.location.pathname) return; if (!targetUrl.hash) return; if (!findHashTarget(targetUrl.hash)) return; e.preventDefault(); scrollToHash(targetUrl.hash, 'smooth'); if (menuToggle && headerNav) { menuToggle.classList.remove('active'); headerNav.classList.remove('active'); } if (window.history && typeof window.history.pushState === 'function') { window.history.pushState(null, '', targetUrl.hash); } }); window.addEventListener('scroll', onScroll, { passive: true }); window.addEventListener('resize', function() { cachedCompactHeight = null; updateHeaderState(); }); window.addEventListener('load', function() { updateHeaderState(); if (window.location.hash) { setTimeout(function() { scrollToHash(window.location.hash, 'auto'); }, 0); } }); updateHeaderState(); // Logo click: scroll to top on home page, navigate to / on other pages document.addEventListener('click', function(e) { var logo = e.target.closest('.block-header .logo'); if (!logo) return; var loc = window.location; // Resolve the logo href to absolute path var resolved; try { resolved = new URL(logo.href, loc.href); } catch(_) { return; } // Check if we're already on the page the logo points to if (resolved.origin === loc.origin && resolved.pathname === loc.pathname) { e.preventDefault(); window.scrollTo({ top: 0, behavior: 'smooth' }); if (loc.hash) history.pushState(null, '', loc.pathname); } // Otherwise let the browser navigate normally }); })(); // Mobile Menu Toggle (function() { const menuToggle = document.querySelector('.mobile-menu-toggle'); const headerNav = document.querySelector('.header-nav'); const menuDropdowns = document.querySelectorAll('.menu-item-dropdown'); if (!menuToggle || !headerNav) return; // Toggle mobile menu menuToggle.addEventListener('click', function(e) { e.stopPropagation(); menuToggle.classList.toggle('active'); headerNav.classList.toggle('active'); }); // Close menu when clicking outside document.addEventListener('click', function(e) { if (!headerNav.contains(e.target) && !menuToggle.contains(e.target)) { menuToggle.classList.remove('active'); headerNav.classList.remove('active'); } }); // Handle dropdown menus on mobile menuDropdowns.forEach(dropdown => { const link = dropdown.querySelector('.menu-item-has-children'); if (link) { link.addEventListener('click', function(e) { if (window.innerWidth <= 768) { e.preventDefault(); dropdown.classList.toggle('active'); } }); } }); // Close mobile menu when window is resized to desktop window.addEventListener('resize', function() { if (window.innerWidth > 768) { menuToggle.classList.remove('active'); headerNav.classList.remove('active'); menuDropdowns.forEach(dropdown => { dropdown.classList.remove('active'); }); } }); })(); // Scroll to Top Button (function() { const scrollToTopBtn = document.getElementById('scrollToTop'); if (!scrollToTopBtn) return; // Show/hide button based on scroll position function toggleScrollButton() { if (window.pageYOffset > 300) { scrollToTopBtn.classList.add('visible'); } else { scrollToTopBtn.classList.remove('visible'); } } // Scroll to top when button is clicked function scrollToTop() { window.scrollTo({ top: 0, behavior: 'smooth' }); } // Event listeners window.addEventListener('scroll', toggleScrollButton); scrollToTopBtn.addEventListener('click', scrollToTop); // Initial check toggleScrollButton(); })(); // Cookie Consent Banner (function() { const cookieBanner = document.getElementById('cookieConsent'); const acceptButton = document.getElementById('cookieConsentBtn'); const COOKIE_CONSENT_KEY = 'cookieConsentAccepted'; if (!cookieBanner || !acceptButton) return; // Check if user has already accepted cookies function hasAcceptedCookies() { return localStorage.getItem(COOKIE_CONSENT_KEY) === 'true'; } // Show banner if consent not given function showBanner() { if (!hasAcceptedCookies()) { setTimeout(function() { cookieBanner.classList.add('show'); }, 1000); // Show after 1 second delay } } // Hide banner and save consent function acceptCookies() { cookieBanner.classList.remove('show'); localStorage.setItem(COOKIE_CONSENT_KEY, 'true'); // Remove from DOM after animation setTimeout(function() { cookieBanner.remove(); }, 400); } // Event listener for accept button acceptButton.addEventListener('click', acceptCookies); // Initialize showBanner(); })(); // Testimonials Carousel Navigation (function() { const testimonialsSection = document.querySelector('.block-testimonials'); if (!testimonialsSection) return; const grid = testimonialsSection.querySelector('.testimonials-grid'); const prevBtn = testimonialsSection.querySelector('.testimonials-nav-prev'); const nextBtn = testimonialsSection.querySelector('.testimonials-nav-next'); const dots = testimonialsSection.querySelectorAll('.testimonials-dot'); const items = testimonialsSection.querySelectorAll('.testimonial-item'); if (!grid || !prevBtn || !nextBtn || dots.length === 0) return; let currentIndex = 0; // Scroll to specific testimonial function scrollToTestimonial(index) { if (index < 0 || index >= items.length) return; currentIndex = index; const item = items[index]; const scrollLeft = item.offsetLeft - grid.offsetLeft; grid.scrollTo({ left: scrollLeft, behavior: 'smooth' }); updateActiveDot(); updateNavButtons(); } // Update active dot indicator function updateActiveDot() { dots.forEach(function(dot, index) { if (index === currentIndex) { dot.classList.add('active'); } else { dot.classList.remove('active'); } }); } // Update navigation button states function updateNavButtons() { prevBtn.disabled = currentIndex === 0; nextBtn.disabled = currentIndex === items.length - 1; } // Navigate to previous testimonial function prevTestimonial() { if (currentIndex > 0) { scrollToTestimonial(currentIndex - 1); } } // Navigate to next testimonial function nextTestimonial() { if (currentIndex < items.length - 1) { scrollToTestimonial(currentIndex + 1); } } // Update current index based on scroll position function updateIndexFromScroll() { const scrollLeft = grid.scrollLeft; let newIndex = 0; let minDistance = Infinity; items.forEach(function(item, index) { const itemLeft = item.offsetLeft - grid.offsetLeft; const distance = Math.abs(scrollLeft - itemLeft); if (distance < minDistance) { minDistance = distance; newIndex = index; } }); if (newIndex !== currentIndex) { currentIndex = newIndex; updateActiveDot(); updateNavButtons(); } } // Event listeners prevBtn.addEventListener('click', prevTestimonial); nextBtn.addEventListener('click', nextTestimonial); dots.forEach(function(dot) { dot.addEventListener('click', function() { const index = parseInt(this.getAttribute('data-index'), 10); scrollToTestimonial(index); }); }); // Update on scroll let scrollTimeout; grid.addEventListener('scroll', function() { clearTimeout(scrollTimeout); scrollTimeout = setTimeout(updateIndexFromScroll, 100); }); // Initial setup updateNavButtons(); })(); // Fortune Wheel Widget (function() { var canvases = document.querySelectorAll('.fortune-wheel-canvas'); if (!canvases.length) return; canvases.forEach(function(canvas) { var widget = canvas.closest('.fortune-wheel-widget'); if (!widget) return; var ctx = canvas.getContext('2d'); var segments = JSON.parse(canvas.dataset.segments || '[]'); var spinDuration = parseFloat(canvas.dataset.spinDuration) || 4; var spinBtn = widget.querySelector('.fortune-wheel-spin-btn'); var resultBox = widget.querySelector('.fortune-wheel-result'); var resultText = widget.querySelector('.fortune-wheel-result-text'); if (!segments.length) return; var segmentCount = segments.length; var arcSize = (2 * Math.PI) / segmentCount; var currentAngle = 0; var isSpinning = false; var defaultColors = [ '#FF6B6B', '#6366F1', '#10B981', '#F59E0B', '#EC4899', '#8B5CF6', '#14B8A6', '#EF4444', '#3B82F6', '#22C55E', '#A855F7', '#F97316' ]; function drawWheel(angle) { var centerX = canvas.width / 2; var centerY = canvas.height / 2; var radius = Math.min(centerX, centerY) - 8; ctx.clearRect(0, 0, canvas.width, canvas.height); // Outer ring ctx.beginPath(); ctx.arc(centerX, centerY, radius + 4, 0, 2 * Math.PI); ctx.lineWidth = 6; ctx.strokeStyle = 'rgba(255,255,255,0.3)'; ctx.stroke(); for (var i = 0; i < segmentCount; i++) { var startAngle = angle + i * arcSize; var endAngle = startAngle + arcSize; var segColor = segments[i].color || defaultColors[i % defaultColors.length]; // Segment ctx.beginPath(); ctx.moveTo(centerX, centerY); ctx.arc(centerX, centerY, radius, startAngle, endAngle); ctx.closePath(); ctx.fillStyle = segColor; ctx.fill(); ctx.lineWidth = 2; ctx.strokeStyle = 'rgba(255,255,255,0.3)'; ctx.stroke(); // Label ctx.save(); ctx.translate(centerX, centerY); ctx.rotate(startAngle + arcSize / 2); ctx.textAlign = 'right'; ctx.fillStyle = '#fff'; ctx.font = 'bold ' + Math.max(11, Math.floor(140 / segmentCount)) + 'px sans-serif'; ctx.shadowColor = 'rgba(0,0,0,0.5)'; ctx.shadowBlur = 3; ctx.fillText(segments[i].label, radius - 16, 5); ctx.restore(); } // Center circle ctx.beginPath(); ctx.arc(centerX, centerY, 22, 0, 2 * Math.PI); ctx.fillStyle = '#fff'; ctx.fill(); ctx.shadowColor = 'transparent'; ctx.shadowBlur = 0; ctx.beginPath(); ctx.arc(centerX, centerY, 18, 0, 2 * Math.PI); ctx.fillStyle = '#333'; ctx.fill(); } function spin() { if (isSpinning) return; isSpinning = true; spinBtn.disabled = true; var totalRotation = (5 + Math.random() * 3) * 2 * Math.PI; var targetAngle = currentAngle + totalRotation; var startTime = null; var duration = spinDuration * 1000; function easeOut(t) { return 1 - Math.pow(1 - t, 3); } function animate(time) { if (!startTime) startTime = time; var elapsed = time - startTime; var progress = Math.min(elapsed / duration, 1); var easedProgress = easeOut(progress); var angle = currentAngle + (targetAngle - currentAngle) * easedProgress; drawWheel(angle); if (progress < 1) { requestAnimationFrame(animate); } else { currentAngle = targetAngle % (2 * Math.PI); isSpinning = false; // Winner: pointer is at top = -PI/2 in canvas coords var pointerAngle = -Math.PI / 2; var relativeAngle = (pointerAngle - currentAngle) % (2 * Math.PI); if (relativeAngle < 0) relativeAngle += 2 * Math.PI; var winIndex = Math.floor(relativeAngle / arcSize) % segmentCount; var winner = segments[winIndex]; // Hide spin button spinBtn.style.display = 'none'; // Show modal popup var modal = widget.querySelector('.fortune-wheel-modal'); if (modal && resultText) { resultText.textContent = winner.value || winner.label; setTimeout(function() { modal.classList.add('active'); }, 300); } } } requestAnimationFrame(animate); } // Close modal var modalClose = widget.querySelector('.fortune-wheel-modal-close'); if (modalClose) { modalClose.addEventListener('click', function() { var modal = widget.querySelector('.fortune-wheel-modal'); if (modal) modal.classList.remove('active'); }); } drawWheel(currentAngle); if (spinBtn) spinBtn.addEventListener('click', spin); }); })(); // Slot Machine Widget (function() { var machines = document.querySelectorAll('.slot-machine-widget'); if (!machines.length) return; machines.forEach(function(widget) { var reelsData = JSON.parse(widget.dataset.reels || '[]'); var prizesData = JSON.parse(widget.dataset.prizes || '[]'); var spinDuration = (parseFloat(widget.dataset.spinDuration) || 2) * 1000; var spinBtn = widget.querySelector('.slot-machine-spin-btn'); var reelEls = widget.querySelectorAll('.slot-reel'); var resultText = widget.querySelector('.slot-machine-result-text'); var isSpinning = false; if (!reelsData.length || !reelEls.length) return; var symbolHeight = 100; // matches CSS .slot-symbol height var reelCount = reelEls.length; // Build extended reel strips for smooth scrolling reelEls.forEach(function(reelEl, i) { var strip = reelEl.querySelector('.slot-reel-strip'); var symbols = reelsData[i] || reelsData[0]; // Clone symbols enough times for smooth animation var html = ''; for (var repeat = 0; repeat < 20; repeat++) { for (var s = 0; s < symbols.length; s++) { html += '<div class="slot-symbol">' + symbols[s] + '</div>'; } } strip.innerHTML = html; }); function spin() { if (isSpinning) return; isSpinning = true; spinBtn.disabled = true; // Determine final symbols for each reel var finalSymbols = []; for (var i = 0; i < reelCount; i++) { var symbols = reelsData[i] || reelsData[0]; var idx = Math.floor(Math.random() * symbols.length); finalSymbols.push({ index: idx, symbol: symbols[idx] }); } // Animate each reel with staggered stop var completed = 0; reelEls.forEach(function(reelEl, i) { var strip = reelEl.querySelector('.slot-reel-strip'); var symbols = reelsData[i] || reelsData[0]; var symbolCount = symbols.length; var targetIdx = finalSymbols[i].index; // Total distance: several full cycles + target position var fullCycles = 4 + i * 2; // More cycles for later reels var targetPos = (fullCycles * symbolCount + targetIdx) * symbolHeight; reelEl.classList.add('spinning'); var startTime = null; var duration = spinDuration + i * 500; // Stagger: each reel takes longer function easeOut(t) { return 1 - Math.pow(1 - t, 3); } function animate(time) { if (!startTime) startTime = time; var elapsed = time - startTime; var progress = Math.min(elapsed / duration, 1); var easedProgress = easeOut(progress); var currentPos = targetPos * easedProgress; strip.style.transform = 'translateY(-' + currentPos + 'px)'; if (progress < 1) { requestAnimationFrame(animate); } else { reelEl.classList.remove('spinning'); reelEl.classList.add('stopped'); completed++; if (completed === reelCount) { onSpinComplete(finalSymbols); } } } requestAnimationFrame(animate); }); } function onSpinComplete(finalSymbols) { isSpinning = false; // Check result var resultSymbols = finalSymbols.map(function(s) { return s.symbol; }); var allSame = resultSymbols.every(function(s) { return s === resultSymbols[0]; }); // Not a win — allow spinning again if (!allSame) { spinBtn.disabled = false; widget.classList.remove('win'); return; } // WIN! All 3 match — hide button and show prize spinBtn.style.display = 'none'; widget.classList.add('win'); // Find matching prize var prize = null; if (prizesData.length) { for (var p = 0; p < prizesData.length; p++) { var pd = prizesData[p]; if (pd.combination) { var combo = pd.combination; var match = true; for (var c = 0; c < combo.length; c++) { if (combo[c] !== '*' && combo[c] !== resultSymbols[c]) { match = false; break; } } if (match) { prize = pd; break; } } else if (pd.symbol && pd.symbol === resultSymbols[0]) { prize = pd; break; } } // Default prize if (!prize) { for (var d = 0; d < prizesData.length; d++) { if (prizesData[d].default) { prize = prizesData[d]; break; } } } } // Show modal with prize var displayText = prize ? prize.label : (resultSymbols[0] + ' ' + resultSymbols[0] + ' ' + resultSymbols[0]); var modal = widget.querySelector('.slot-machine-modal'); if (modal && resultText) { resultText.textContent = displayText; setTimeout(function() { modal.classList.add('active'); }, 1500); // Delay for win glow animation } } // Close modal var modalClose = widget.querySelector('.slot-machine-modal-close'); if (modalClose) { modalClose.addEventListener('click', function() { var modal = widget.querySelector('.slot-machine-modal'); if (modal) modal.classList.remove('active'); }); } var modalBackdrop = widget.querySelector('.slot-machine-modal-backdrop'); if (modalBackdrop) { modalBackdrop.addEventListener('click', function() { var modal = widget.querySelector('.slot-machine-modal'); if (modal) modal.classList.remove('active'); }); } if (spinBtn) spinBtn.addEventListener('click', spin); }); })();
Save
cmd:
run