1/** 2 * redbasic theme specific JavaScript 3 */ 4 5const redbasic_dark_mode = localStorage.getItem('redbasic_dark_mode'); 6const redbasic_theme_color = localStorage.getItem('redbasic_theme_color'); 7 8if (redbasic_dark_mode == 1) { 9 document.documentElement.setAttribute('data-bs-theme', 'dark'); 10} 11 12if (redbasic_dark_mode == 0) { 13 document.documentElement.setAttribute('data-bs-theme', 'light'); 14} 15 16if (redbasic_theme_color) { 17 document.querySelector('meta[name=theme-color]').setAttribute('content', redbasic_theme_color); 18} 19 20document.addEventListener('DOMContentLoaded', function () { 21 // provide a fake progress bar for pwa standalone mode 22 if (window.matchMedia('(display-mode: standalone)').matches) { 23 window.addEventListener('beforeunload', function () { 24 if (!document.querySelector('.page-loader')) { 25 let loader = document.createElement('div'); 26 loader.classList.add('bg-primary', 'page-loader'); 27 document.body.prepend(loader); 28 } 29 }); 30 } 31 32 if (redbasic_dark_mode == 1) { 33 document.getElementById('theme-switch-icon').classList.remove('bi-moon'); 34 document.getElementById('theme-switch-icon').classList.add('bi-sun'); 35 document.querySelector('[data-bs-theme="light"]').setAttribute('data-bs-theme', 'dark'); 36 } 37 if (redbasic_dark_mode == 0) { 38 document.getElementById('theme-switch-icon').classList.remove('bi-sun'); 39 document.getElementById('theme-switch-icon').classList.add('bi-moon'); 40 let darkElements = document.querySelectorAll('[data-bs-theme="dark"]:not(nav)'); 41 darkElements.forEach(el => el.setAttribute('data-bs-theme', 'light')); 42 } 43 44 const navBackgroundColor = document.querySelector('nav').style.backgroundColor; 45 if (redbasic_theme_color !== navBackgroundColor) { 46 document.querySelector('meta[name=theme-color]').setAttribute('content', navBackgroundColor); 47 localStorage.setItem('redbasic_theme_color', navBackgroundColor); 48 } 49 50 // CSS3 calc() fallback (for unsupported browsers) 51 const testElem = document.createElement('div'); 52 testElem.style.width = 'calc(10px + 10px)'; 53 testElem.style.display = 'none'; 54 testElem.id = 'css3-calc'; 55 document.body.appendChild(testElem); 56 57 if (testElem.offsetWidth === 10) { 58 window.addEventListener('resize', function () { 59 if (window.innerWidth < 992) { 60 document.querySelector('main').style.width = `${window.innerWidth + document.querySelector('aside').offsetWidth}px`; 61 } else { 62 document.querySelector('main').style.width = '100%'; 63 } 64 }); 65 } 66 testElem.remove(); // Remove the test element 67 68 if (window.innerWidth < 1200) { 69 const rightAsideWrapper = document.getElementById("right_aside_wrapper"); 70 const leftAsideWrapper = document.getElementById("left_aside_wrapper"); 71 const notificationsWrapper = document.getElementById("notifications_wrapper"); 72 73 if (leftAsideWrapper && rightAsideWrapper) { 74 const children = rightAsideWrapper.children; 75 if (children.length) { 76 leftAsideWrapper.append(...children); 77 } 78 } 79 80 if (notificationsWrapper) { 81 notificationsWrapper.classList.add('d-none'); 82 } 83 } 84 85 if (document.getElementById('region_1')) { 86 stickyScroll('.aside_spacer_left', '.aside_spacer_top_left', 'section', parseFloat(document.querySelector('main').getBoundingClientRect().top), 20); 87 } 88 89 if (document.getElementById('region_3')) { 90 stickyScroll('.aside_spacer_right', '.aside_spacer_top_right', 'section', parseFloat(document.querySelector('main').getBoundingClientRect().top), 20); 91 } 92 93 document.querySelectorAll('.usermenu').forEach(function (element) { 94 element.addEventListener('click', function () { 95 let navCollapse = document.querySelectorAll('#navbar-collapse-1, #navbar-collapse-2'); 96 navCollapse.forEach(function (nav) { 97 if (nav.classList.contains('show')) { 98 nav.classList.remove('show'); 99 } 100 }); 101 }); 102 }); 103 104 document.getElementById('theme-switch').addEventListener('click', function () { 105 const html = document.documentElement; 106 if (html.getAttribute('data-bs-theme') === 'dark') { 107 let nav = document.querySelector('nav'); 108 if (nav.dataset.bsTheme === 'dark') { 109 document.querySelectorAll('[data-bs-theme="dark"]:not(nav)').forEach(function (el) { 110 el.setAttribute('data-bs-theme', 'light'); 111 }); 112 } else { 113 document.querySelector('[data-bs-theme="dark"]').setAttribute('data-bs-theme', 'light'); 114 } 115 localStorage.setItem('redbasic_dark_mode', 0); 116 document.getElementById('theme-switch-icon').classList.remove('bi-sun'); 117 document.getElementById('theme-switch-icon').classList.add('bi-moon'); 118 } else { 119 document.querySelectorAll('[data-bs-theme="light"]').forEach(function (el) { 120 el.setAttribute('data-bs-theme', 'dark'); 121 }); 122 localStorage.setItem('redbasic_dark_mode', 1); 123 document.getElementById('theme-switch-icon').classList.remove('bi-moon'); 124 document.getElementById('theme-switch-icon').classList.add('bi-sun'); 125 } 126 document.querySelector('meta[name=theme-color]').setAttribute('content', document.querySelector('nav').style.backgroundColor); 127 localStorage.setItem('redbasic_theme_color', document.querySelector('nav').style.backgroundColor); 128 }); 129 130 document.getElementById('menu-btn').addEventListener('click', function () { 131 const navCollapse = document.getElementById('navbar-collapse-1'); 132 if (navCollapse && navCollapse.classList.contains('show')) { 133 navCollapse.classList.remove('show'); 134 } 135 }); 136 137 $("input[data-role=cat-tagsinput]").tagsinput({ 138 tagClass: 'badge rounded-pill bg-warning text-dark' 139 }); 140 141 document.querySelectorAll('a.disabled').forEach(function (link) { 142 link.addEventListener('click', function (e) { 143 e.preventDefault(); 144 e.stopPropagation(); 145 }); 146 }); 147 148 const doctitle = document.title; 149 function checkNotify() { 150 let notifyUpdateElem = document.getElementById('notify-update'); 151 if (notifyUpdateElem && notifyUpdateElem.innerHTML !== '') { 152 document.title = '(' + notifyUpdateElem.innerHTML + ') ' + doctitle; 153 } else { 154 document.title = doctitle; 155 } 156 } 157 158 setInterval(checkNotify, 10 * 1000); 159 160 let touch_start = null; 161 const touch_max = window.innerWidth / 10; 162 163 window.addEventListener('touchstart', function (e) { 164 if (e.touches.length === 1) { 165 touch_start = e.touches[0].clientX; 166 if (touch_start < touch_max) { 167 document.body.style.overflowY = 'hidden'; 168 } 169 } else { 170 touch_start = null; 171 } 172 }); 173 174 window.addEventListener('touchend', function (e) { 175 document.body.style.overflowY = '';
176 let touch_offset = 30; // at least 30px are a swipe 177 if (touch_start) { 178 let touch_end = e.changedTouches[0].clientX; 179 if (touch_end > (touch_start + touch_offset)) { 180 if (touch_start < touch_max) { 181 toggleAside(); 182 } 183 } 184 if (touch_end < (touch_start - touch_offset)) { 185 // a right -> left swipe 186 } 187 } 188 }); 189}); 190 191function setStyle(element, cssProperty) { 192 for (let property in cssProperty) { 193 element.style[property] = cssProperty[property]; 194 } 195} 196 197function stickyScroll(sticky, stickyTop, container, topOffset, bottomOffset) { 198 let lastScrollTop = 0; 199 let stickyElement = document.querySelector(sticky); 200 201 if (!stickyElement) { 202 return; 203 } 204 205 let stickyHeight = stickyElement.getBoundingClientRect().height; 206 const stickyTopElement = document.querySelector(stickyTop); 207 const content = document.querySelector(container); 208 let diff = window.innerHeight - stickyHeight; 209 210 let h = 0; 211 let lasth = 0; 212 let st = window.pageYOffset || document.documentElement.scrollTop; 213 214 let resizeObserver = new ResizeObserver(function () { 215 stickyHeight = stickyElement.getBoundingClientRect().height; 216 st = window.pageYOffset || document.documentElement.scrollTop; 217 diff = window.innerHeight - stickyHeight; 218 }); 219 220 resizeObserver.observe(stickyElement); 221 resizeObserver.observe(content); 222 223 window.addEventListener('scroll', function () { 224 if (window.innerHeight > stickyHeight + topOffset) { 225 setStyle(stickyTopElement, { height: '0px' }); 226 setStyle(stickyElement, { position: 'sticky', top: `${topOffset}px` }); 227 } else { 228 st = window.pageYOffset || document.documentElement.scrollTop; 229 if (st > lastScrollTop) { 230 setStyle(stickyTopElement, { height: `${lasth}px` }); 231 setStyle(stickyElement, { position: 'sticky', top: `${Math.round(diff) - bottomOffset}px`, bottom: '' }); 232 } else { 233 h = stickyElement.getBoundingClientRect().top - content.getBoundingClientRect().top; 234 if (Math.round(stickyTopElement.getBoundingClientRect().height) === lasth) { 235 setStyle(stickyTopElement, { height: `${Math.round(h)}px` }); 236 } 237 lasth = Math.round(h); 238 setStyle(stickyElement, { position: 'sticky', top: '', bottom: `${Math.round(diff) - topOffset}px` }); 239 } 240 lastScrollTop = st <= 0 ? 0 : st; 241 } 242 }, false); 243} 244 245function makeFullScreen(full) { 246 if (typeof full === 'undefined' || full === true) { 247 document.querySelector('main').classList.add('fullscreen'); 248 document.getElementById('fullscreen-btn').style.display = 'none'; 249 document.getElementById('inline-btn').style.display = 'inline-block'; 250 } else { 251 document.querySelector('main').classList.remove('fullscreen'); 252 document.getElementById('fullscreen-btn').style.display = ''; 253 document.getElementById('inline-btn').style.display = 'none'; 254 } 255}
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.