/* ========================================================================== RedGifs Video Downloader — showcase site behaviour No dependencies, no network calls, no tracking. ========================================================================== */ (function () { 'use strict'; var STORAGE_KEY = 'rgvd-lang'; /* ------------------------------------------------------- repository -- ONE place to point the site at the public download location. While the release repository is private, every link below 404s for visitors who are not signed in as its owner. Change REPO_URL once and all nine links follow: data-link="release" -> latest release, data-link="repo" -> repository root, data-link="license" -> LICENSE. The hrefs stay in the HTML as well, so the links still work with JavaScript disabled; this only rewrites them when REPO_URL differs. -------------------------------------------------------------------------- */ var REPO_URL = 'https://git.lonarpgproxy.space/OwnerLink/redgifs-video-downloader'; function initLinks() { var targets = { repo: REPO_URL, release: REPO_URL + '/releases/latest', license: REPO_URL + '/src/branch/main/LICENSE' }; var nodes = document.querySelectorAll('[data-link]'); for (var i = 0; i < nodes.length; i++) { var href = targets[nodes[i].getAttribute('data-link')]; if (href) nodes[i].setAttribute('href', href); } } /* ---------------------------------------------------------------- i18n -- Russian is authored directly in the markup. English lives in the data-en / data-en-alt / data-en-label attributes and is swapped in on demand. The original Russian is cached in data-ru on first switch. -------------------------------------------------------------------------- */ var PAGE_META = { ru: { title: document.title, description: metaContent('description') }, en: { title: document.documentElement.getAttribute('data-en-title') || '', description: document.documentElement.getAttribute('data-en-description') || '' } }; function metaContent(name) { var el = document.querySelector('meta[name="' + name + '"]'); return el ? el.getAttribute('content') : ''; } function setMetaContent(name, value) { var el = document.querySelector('meta[name="' + name + '"]'); if (el && value) el.setAttribute('content', value); } function swapAttribute(el, enAttr, targetAttr, ruAttr, lang) { var en = el.getAttribute(enAttr); if (!en) return; if (!el.hasAttribute(ruAttr)) { el.setAttribute(ruAttr, el.getAttribute(targetAttr) || ''); } el.setAttribute(targetAttr, lang === 'en' ? en : el.getAttribute(ruAttr)); } function applyLanguage(lang) { var isEn = lang === 'en'; document.documentElement.setAttribute('lang', isEn ? 'en' : 'ru'); document.documentElement.setAttribute('data-lang', lang); // Text / markup content var nodes = document.querySelectorAll('[data-en]'); for (var i = 0; i < nodes.length; i++) { var el = nodes[i]; if (!el.hasAttribute('data-ru')) { el.setAttribute('data-ru', el.innerHTML); } // Both sides are authored in this repository, never user input. el.innerHTML = isEn ? el.getAttribute('data-en') : el.getAttribute('data-ru'); } // Accessible names that are not text content var alts = document.querySelectorAll('[data-en-alt]'); for (var a = 0; a < alts.length; a++) { swapAttribute(alts[a], 'data-en-alt', 'alt', 'data-ru-alt', lang); } var labels = document.querySelectorAll('[data-en-label]'); for (var b = 0; b < labels.length; b++) { swapAttribute(labels[b], 'data-en-label', 'aria-label', 'data-ru-label', lang); } // Document metadata if (PAGE_META[lang] && PAGE_META[lang].title) { document.title = PAGE_META[lang].title; } if (PAGE_META[lang] && PAGE_META[lang].description) { setMetaContent('description', PAGE_META[lang].description); } // Switch buttons var buttons = document.querySelectorAll('[data-set-lang]'); for (var c = 0; c < buttons.length; c++) { buttons[c].setAttribute( 'aria-pressed', buttons[c].getAttribute('data-set-lang') === lang ? 'true' : 'false' ); } } function storedLanguage() { var stored = null; try { stored = window.localStorage.getItem(STORAGE_KEY); } catch (err) { stored = null; } if (stored === 'ru' || stored === 'en') return stored; var nav = (navigator.language || '').toLowerCase(); var list = navigator.languages || []; for (var i = 0; i < list.length; i++) { if (String(list[i]).toLowerCase().indexOf('ru') === 0) return 'ru'; } return nav.indexOf('ru') === 0 ? 'ru' : 'en'; } function initLanguage() { var buttons = document.querySelectorAll('[data-set-lang]'); if (!buttons.length) return; applyLanguage(storedLanguage()); for (var i = 0; i < buttons.length; i++) { buttons[i].addEventListener('click', function () { var lang = this.getAttribute('data-set-lang'); applyLanguage(lang); try { window.localStorage.setItem(STORAGE_KEY, lang); } catch (err) { /* private mode — the choice simply is not remembered */ } }); } } /* ------------------------------------------------------------- header -- */ function initHeader() { var header = document.getElementById('siteHeader'); if (!header) return; var ticking = false; function update() { header.classList.toggle('is-stuck', window.scrollY > 8); ticking = false; } window.addEventListener('scroll', function () { if (!ticking) { ticking = true; window.requestAnimationFrame(update); } }, { passive: true }); update(); } /* ---------------------------------------------------------- mobile nav -- */ function initNav() { var toggle = document.getElementById('navToggle'); var nav = document.getElementById('primaryNav'); if (!toggle || !nav) return; function close() { nav.classList.remove('is-open'); toggle.setAttribute('aria-expanded', 'false'); } toggle.addEventListener('click', function () { var open = nav.classList.toggle('is-open'); toggle.setAttribute('aria-expanded', open ? 'true' : 'false'); }); nav.addEventListener('click', function (event) { if (event.target.closest('a')) close(); }); document.addEventListener('keydown', function (event) { if (event.key === 'Escape') close(); }); document.addEventListener('click', function (event) { if (!nav.classList.contains('is-open')) return; if (nav.contains(event.target) || toggle.contains(event.target)) return; close(); }); } /* ------------------------------------------------------------- reveal -- */ function initReveal() { var items = document.querySelectorAll('.reveal'); if (!items.length) return; var reduced = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches; if (reduced || !('IntersectionObserver' in window)) { for (var i = 0; i < items.length; i++) items[i].classList.add('is-visible'); return; } var observer = new IntersectionObserver(function (entries) { entries.forEach(function (entry) { if (!entry.isIntersecting) return; entry.target.classList.add('is-visible'); observer.unobserve(entry.target); }); }, { rootMargin: '0px 0px -8% 0px', threshold: 0.08 }); for (var j = 0; j < items.length; j++) { // Stagger siblings a little so grids cascade instead of popping. var delay = (j % 4) * 70; items[j].style.transitionDelay = delay + 'ms'; observer.observe(items[j]); } } /* ---------------------------------------------------------------- boot -- */ function boot() { initLinks(); initLanguage(); initHeader(); initNav(); initReveal(); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', boot); } else { boot(); } })();