PageSourceSearch

https://ownwebservers.com/blog/wp-content/themes/ows-kb/js/theme.js?ver=1.4.1

js ownwebservers.com collected 2026-10-08 12:25:04 UTC 3,712 bytes, 108 lines download raw bytes

1(function () {
2  'use strict';
3
4  /* ---- Sticky-header background on scroll ---- */
5  var header = document.getElementById('ows-header');
6  function onScroll() {
7    if (!header) return;
8    header.classList.toggle('is-scrolled', window.scrollY > 8);
9  }
10  window.addEventListener('scroll', onScroll, { passive: true });
11  onScroll();
12
13  /* ---- Mobile burger toggle ---- */
14  var burger = document.getElementById('ows-burger');
15  var mobile = document.getElementById('ows-mobile');
16  if (burger && mobile) {
17    burger.addEventListener('click', function () {
18      var open = mobile.classList.toggle('is-open');
19      burger.setAttribute('aria-expanded', open ? 'true' : 'false');
20    });
21    // Close when a leaf link (no sub-menu sibling) is followed.
22    mobile.addEventListener('click', function (e) {
23      var link = e.target.closest('a');
24      if (!link) return;
25      var parentLi = link.parentElement;
26      var hasSub = parentLi && parentLi.querySelector(':scope > .sub-menu');
27      if (!hasSub) {
28        mobile.classList.remove('is-open');
29        burger.setAttribute('aria-expanded', 'false');
30      }
31    });
32  }
33
34  /* ---- Mobile sub-menu accordion ---- */
35  // Target <li class="menu-item-has-children"> inside .ows-mobile nav.
36  var mobileNav = mobile ? mobile.querySelector('nav') : null;
37  if (mobileNav) {
38    var parents = mobileNav.querySelectorAll('.menu-item-has-children');
39    parents.forEach(function (li) {
40      var trigger = li.querySelector(':scope > a');
41      var sub = li.querySelector(':scope > .sub-menu');
42      if (!trigger || !sub) return;
43
44      // Prevent navigation when toggling a parent that only has hash href.
45      trigger.addEventListener('click', function (e) {
46        var href = trigger.getAttribute('href');
47        if (!href || href === '#') {
48          e.preventDefault();
49        }
50        // Close siblings.
51        parents.forEach(function (sibling) {
52          if (sibling !== li && sibling.parentElement === li.parentElement) {
53            sibling.classList.remove('is-open');
54          }
55        });
56        li.classList.toggle('is-open');
57      });
58    });
59  }
60
61  /* ---- Desktop dropdown: close on Escape ---- */
62  document.addEventListener('keydown', function (e) {
63    if (e.key === 'Escape') {
64      var focused = document.activeElement;
65      if (focused) focused.blur();
66    }
67  });
68
69  /* ---- Dark / Light theme toggle ---- */
70  var themeToggle = document.getElementById('ows-theme-toggle');
71  var themeMeta   = document.getElementById('ows-theme-meta');
72
73  function applyTheme(theme) {
74    document.documentElement.setAttribute('data-theme', theme);
75    localStorage.setItem('ows-theme', theme);
76    if (themeMeta) {
77      themeMeta.content = theme === 'light' ? '#f8fafc' : '#0a0e1a';
78    }
79    if (themeToggle) {
80      themeToggle.setAttribute(
81        'aria-label',
82        theme === 'light' ? 'Switch to dark mode' : 'Switch to light mode'
83      );
84    }
85  }
86
87  if (themeToggle) {
88    // Set initial aria-label
89    var initialTheme = document.documentElement.getAttribute('data-theme') || 'dark';
90    themeToggle.setAttribute(
91      'aria-label',
92      initialTheme === 'light' ? 'Switch to dark mode' : 'Switch to light mode'
93    );
94
95    themeToggle.addEventListener('click', function () {
96      var current = document.documentElement.getAttribute('data-theme') || 'dark';
97      applyTheme(current === 'light' ? 'dark' : 'light');
98    });
99  }
100
101  // React to system preference changes (when no manual override has been saved).
102  window.matchMedia('(prefers-color-scheme: light)').addEventListener('change', function (e) {
103    if (!localStorage.getItem('ows-theme')) {
104      applyTheme(e.matches ? 'light' : 'dark');
105    }
106  });
107
108})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.