v1.0.0.0
StocketBase
- (function () {
- 'use strict';
-
- var THEME_KEY = 'stocketbase_theme';
-
- function applyTheme(theme) {
- document.body.setAttribute('data-theme', theme);
- }
-
- function initTheme() {
- var stored = localStorage.getItem(THEME_KEY);
- if (stored === 'dark' || stored === 'light') {
- applyTheme(stored);
- return;
- }
- var prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
- applyTheme(prefersDark ? 'dark' : 'light');
- }
-
- function toggleTheme() {
- var current = document.body.getAttribute('data-theme') || 'light';
- var next = current === 'dark' ? 'light' : 'dark';
- applyTheme(next);
- localStorage.setItem(THEME_KEY, next);
- }
-
- function initConsent() {
- var banner = document.getElementById('consent-banner');
- var acceptBtn = document.getElementById('consent-accept');
- var declineBtn = document.getElementById('consent-decline');
- var consentKey = 'stocketbase_consent';
-
- function runGatedScripts() {
- document.querySelectorAll('script.consent-gated-script').forEach(function (oldScript) {
- var newScript = document.createElement('script');
- Array.from(oldScript.attributes).forEach(function (attr) {
- if (attr.name !== 'type') {
- newScript.setAttribute(attr.name, attr.value);
- }
- });
- newScript.textContent = oldScript.textContent;
- oldScript.parentNode.replaceChild(newScript, oldScript);
- });
- }
-
- var reopenBtn = document.getElementById('consent-reopen-btn');
- var storedConsent = localStorage.getItem(consentKey);
- var scriptsRan = false;
-
- function hideBanner() {
- if (banner) { banner.style.display = 'none'; }
- }
-
- if (storedConsent === 'accepted') {
- runGatedScripts();
- scriptsRan = true;
- }
- if (storedConsent) {
- hideBanner();
- }
-
- if (acceptBtn) {
- acceptBtn.addEventListener('click', function () {
- localStorage.setItem(consentKey, 'accepted');
- if (!scriptsRan) {
- runGatedScripts();
- scriptsRan = true;
- }
- hideBanner();
- });
- }
- if (declineBtn) {
- declineBtn.addEventListener('click', function () {
- localStorage.setItem(consentKey, 'declined');
- if (scriptsRan) {
- window.location.reload();
- return;
- }
- hideBanner();
- });
- }
- if (reopenBtn && banner) {
- reopenBtn.addEventListener('click', function () {
- banner.style.display = '';
- });
- }
- }
-
- function initPagination() {
- var list = document.getElementById('article-list');
- if (!list) {
- return;
- }
-
- var source = list.dataset.paginationSource;
- if (source !== 'home' && source !== 'category' && source !== 'search') {
- return;
- }
-
- var categorySlug = list.dataset.categorySlug || '';
- var searchQuery = list.dataset.searchQuery || '';
- var searchCategory = list.dataset.searchCategory || '';
- var searchTag = list.dataset.searchTag || '';
- var searchSort = list.dataset.searchSort || '';
- var loading = false;
-
- function fetchPage(page) {
- if (loading) {
- return;
- }
- loading = true;
-
- var url = 'products-fragment.php?source=' + encodeURIComponent(source) + '&page=' + encodeURIComponent(page);
- if (source === 'category') {
- url += '&slug=' + encodeURIComponent(categorySlug);
- }
- if (source === 'search') {
- url += '&q=' + encodeURIComponent(searchQuery);
- if (searchCategory && searchCategory !== '0') {
- url += '&category=' + encodeURIComponent(searchCategory);
- }
- if (searchTag && searchTag !== '0') {
- url += '&tag=' + encodeURIComponent(searchTag);
- }
- if (searchSort) {
- url += '&sort=' + encodeURIComponent(searchSort);
- }
- }
-
- fetch(url)
- .then(function (response) {
- if (!response.ok) {
- throw new Error('Request failed');
- }
- return response.text();
- })
- .then(function (html) {
- var temp = document.createElement('div');
- temp.innerHTML = html;
-
- var newCards = temp.querySelectorAll('.product-card');
- newCards.forEach(function (card) {
- list.appendChild(card);
- });
-
- var container = document.getElementById('pagination-container');
- if (container) {
- var newControl = temp.querySelector('.pagination-load-more, .pagination-infinite-marker, .pagination-end');
- container.innerHTML = '';
- if (newControl) {
- container.appendChild(newControl);
- bindControl(newControl);
- }
- }
-
- loading = false;
- })
- .catch(function () {
- loading = false;
- });
- }
-
- function bindControl(control) {
- if (!control) {
- return;
- }
-
- if (control.classList.contains('pagination-load-more')) {
- var btn = control.querySelector('.pagination-load-more-btn');
- if (btn) {
- btn.addEventListener('click', function () {
- fetchPage(control.dataset.nextPage);
- });
- }
- return;
- }
-
- if (control.classList.contains('pagination-infinite-marker')) {
- if (!('IntersectionObserver' in window)) {
- return;
- }
- var observer = new IntersectionObserver(function (entries) {
- entries.forEach(function (entry) {
- if (entry.isIntersecting) {
- observer.disconnect();
- fetchPage(control.dataset.nextPage);
- }
- });
- }, { rootMargin: '200px' });
- observer.observe(control);
- }
- }
-
- var container = document.getElementById('pagination-container');
- if (container) {
- bindControl(container.querySelector('.pagination-load-more, .pagination-infinite-marker'));
- }
- }
-
- function initBrandShortName() {
- var brand = document.querySelector('.site-brand[data-short-name]');
- var header = document.querySelector('.site-header');
-
- if (!brand || !header) {
- return;
- }
-
- function overflows() {
- return brand.scrollWidth > brand.clientWidth + 1 || header.scrollWidth > header.clientWidth + 1;
- }
-
- function update() {
- brand.classList.remove('use-short');
- if (overflows()) {
- brand.classList.add('use-short');
- }
- }
-
- update();
- window.addEventListener('resize', update);
- window.addEventListener('load', update);
- }
-
- function initMobileNav() {
- var toggle = document.getElementById('site-menu-toggle');
- var nav = document.getElementById('site-nav');
- var backdrop = document.getElementById('site-nav-backdrop');
- var header = document.querySelector('.site-header');
-
- if (!toggle || !nav || !backdrop) {
- return;
- }
-
- var lockedScrollY = 0;
-
- function openNav() {
- nav.classList.add('is-open');
- backdrop.classList.add('is-open');
- toggle.setAttribute('aria-expanded', 'true');
- lockedScrollY = window.scrollY || window.pageYOffset || 0;
- document.body.style.position = 'fixed';
- document.body.style.top = -lockedScrollY + 'px';
- document.body.style.left = '0';
- document.body.style.right = '0';
- if (header) {
- header.classList.add('site-nav-drawer-open');
- }
- }
-
- function closeNav() {
- nav.classList.remove('is-open');
- backdrop.classList.remove('is-open');
- toggle.setAttribute('aria-expanded', 'false');
- document.body.style.position = '';
- document.body.style.top = '';
- document.body.style.left = '';
- document.body.style.right = '';
- window.scrollTo(0, lockedScrollY);
- if (header) {
- header.classList.remove('site-nav-drawer-open');
- }
- }
-
- toggle.addEventListener('click', function () {
- if (nav.classList.contains('is-open')) {
- closeNav();
- } else {
- openNav();
- }
- });
-
- backdrop.addEventListener('click', closeNav);
-
- nav.querySelectorAll('a').forEach(function (link) {
- link.addEventListener('click', closeNav);
- });
-
- window.addEventListener('resize', function () {
- if (window.innerWidth > 860) {
- closeNav();
- }
- });
- }
-
- function initShare() {
- var toggle = document.getElementById('share-toggle-btn');
- var panel = document.getElementById('share-panel');
- var copyBtn = document.getElementById('share-copy-btn');
-
- if (!toggle || !panel) {
- return;
- }
-
- function closePanel() {
- panel.classList.remove('is-open');
- toggle.setAttribute('aria-expanded', 'false');
- }
-
- function openPanel() {
- panel.classList.add('is-open');
- toggle.setAttribute('aria-expanded', 'true');
- }
-
- toggle.addEventListener('click', function (event) {
- event.stopPropagation();
- if (panel.classList.contains('is-open')) {
- closePanel();
- } else {
- openPanel();
- }
- });
-
- document.addEventListener('click', function (event) {
- if (panel.classList.contains('is-open') && !panel.contains(event.target) && event.target !== toggle) {
- closePanel();
- }
- });
-
- document.addEventListener('keydown', function (event) {
- if (event.key === 'Escape') {
- closePanel();
- }
- });
-
- if (copyBtn) {
- copyBtn.addEventListener('click', function () {
- var url = copyBtn.getAttribute('data-share-url') || window.location.href;
- var label = copyBtn.querySelector('.js-share-copy-label');
- var defaultText = copyBtn.getAttribute('data-default-text') || '';
- var copiedText = copyBtn.getAttribute('data-copied-text') || '';
-
- function showCopied() {
- if (label && copiedText) {
- label.textContent = copiedText;
- setTimeout(function () {
- label.textContent = defaultText;
- }, 2000);
- }
- }
-
- if (navigator.clipboard && navigator.clipboard.writeText) {
- navigator.clipboard.writeText(url).then(showCopied);
- } else {
- var tempInput = document.createElement('input');
- tempInput.value = url;
- document.body.appendChild(tempInput);
- tempInput.select();
- document.execCommand('copy');
- document.body.removeChild(tempInput);
- showCopied();
- }
- });
- }
- }
-
- function initAppBanner() {
- var banner = document.getElementById('app-banner');
- if (!banner) {
- return;
- }
-
- var DISMISS_KEY = 'stocketbase_app_banner_dismissed';
-
- try {
- if (localStorage.getItem(DISMISS_KEY) === '1') {
- banner.remove();
- return;
- }
- } catch (e) {}
-
- var userAgent = navigator.userAgent || '';
- var isAndroid = /Android/i.test(userAgent);
- var isIOS = /iPhone|iPad|iPod/i.test(userAgent);
- var androidUrl = banner.getAttribute('data-android-url') || '';
- var iosUrl = banner.getAttribute('data-ios-url') || '';
-
- var targetUrl = '';
- if (isAndroid && androidUrl) {
- targetUrl = androidUrl;
- } else if (isIOS && iosUrl) {
- targetUrl = iosUrl;
- }
-
- if (!targetUrl) {
- banner.remove();
- return;
- }
-
- var link = document.getElementById('app-banner-link');
- if (link) {
- link.setAttribute('href', targetUrl);
- }
-
- banner.classList.add('is-visible');
-
- var closeBtn = document.getElementById('app-banner-close');
- if (closeBtn) {
- closeBtn.addEventListener('click', function () {
- banner.classList.remove('is-visible');
- try {
- localStorage.setItem(DISMISS_KEY, '1');
- } catch (e) {}
- });
- }
- }
-
- function initBackToTop() {
- var button = document.getElementById('back-to-top');
- if (!button) {
- return;
- }
-
- var label = button.querySelector('.back-to-top-progress');
- var content = button.getAttribute('data-progress') === '1' ? document.querySelector('.article-content') : null;
- var template = button.getAttribute('data-left-text') || '{percent}%';
- var reduceMotion = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
- var ticking = false;
-
- if (content && label) {
- button.classList.add('has-progress');
- label.hidden = false;
- }
-
- function update() {
- ticking = false;
-
- var visible = (window.pageYOffset || 0) > 400;
- button.classList.toggle('is-visible', visible);
- button.tabIndex = visible ? 0 : -1;
-
- if (content && label) {
- var rect = content.getBoundingClientRect();
- var read = rect.height > 0 ? Math.min(1, Math.max(0, (window.innerHeight - rect.top) / rect.height)) : 1;
- var percentRead = Math.round(read * 100);
- label.textContent = template.replace('{percent}', String(100 - percentRead));
- button.style.setProperty('--btt-read', percentRead + '%');
- }
- }
-
- function schedule() {
- if (!ticking) {
- ticking = true;
- requestAnimationFrame(update);
- }
- }
-
- window.addEventListener('scroll', schedule, { passive: true });
- window.addEventListener('resize', schedule);
- button.addEventListener('click', function () {
- window.scrollTo({ top: 0, behavior: reduceMotion ? 'auto' : 'smooth' });
- });
- update();
- }
-
- document.addEventListener('DOMContentLoaded', function () {
- initTheme();
- initBackToTop();
- var toggleBtn = document.getElementById('theme-toggle-btn');
- if (toggleBtn) {
- toggleBtn.addEventListener('click', toggleTheme);
- }
- initConsent();
- initPagination();
- initMobileNav();
- initBrandShortName();
- initShare();
- initAppBanner();
- });
- })();
-
- (function () {
- var switcher = document.querySelector('[data-language-switcher]');
- if (!switcher) {
- return;
- }
-
- document.addEventListener('click', function (event) {
- if (switcher.open && !switcher.contains(event.target)) {
- switcher.open = false;
- }
- });
-
- document.addEventListener('keydown', function (event) {
- if (event.key === 'Escape' && switcher.open) {
- switcher.open = false;
- switcher.querySelector('summary').focus();
- }
- });
- })();
-