1(function() { 2 // Find or create footer element 3 let footer = document.querySelector('footer.footer'); 4 if (!footer) { 5 footer = document.createElement('footer'); 6 footer.className = 'footer'; 7 document.body.appendChild(footer); 8 } 9 10 footer.innerHTML = ` 11 <div class="footer-container"> 12 <div class="footer-main"> 13 <div class="footer-brand"> 14 <a href="/" class="footer-logo"><img src="/assets/images/nametype.avif" alt="Otakiroku"></a> 15 <span class="footer-copyright">© ${new Date().getFullYear()} Otakiroku</span> 16 </div> 17 <div class="footer-column"> 18 <h4>Browse</h4> 19 <ul class="footer-links"> 20 <li><a href="/anime" data-page="anime">Anime</a></li> 21 <li><a href="/manga" data-page="manga">Manga</a></li> 22 <li><a href="/forum" data-page="forum">Forum</a></li> 23 </ul> 24 </div> 25 <div class="footer-column"> 26 <h4>Account</h4> 27 <ul class="footer-links"> 28 <li><a href="/user" data-page="user">Profile</a></li> 29 <li><a href="/user?tab=settings" data-page="user">Settings</a></li> 30 </ul> 31 </div> 32 <div class="footer-column"> 33 <h4>Resources</h4> 34 <ul class="footer-links"> 35 <li><a href="/about">About Otakiroku</a></li> 36 <li><a href="/changelog">Changelog</a></li> 37 <li><a href="/extension" data-page="extension">OKU Link Extension</a></li> 38 </ul> 39 </div> 40 <div class="footer-column"> 41 <h4>Support</h4> 42 <ul class="footer-links"> 43 <li><a href="/contact">Contact Us</a></li> 44 <li><a href="#" onclick="BugReportModal.open(); return false;">Report a Bug</a></li> 45 <li><a href="/terms">Terms & Guidelines</a></li> 46 </ul> 47 </div> 48 </div> 49 </div> 50 `; 51 52 // Update footer link visibility based on feature toggles 53 async function updateFooterVisibility() { 54 try { 55 // Use GraphQL if available 56 let pages = {}; 57 let hiddenStates = {}; 58 59 if (window.GraphQL && typeof window.GraphQL.getFeatures === 'function') { 60 const features = await window.GraphQL.getFeatures(); 61 if (features) { 62 for (const f of features) { 63 if (f.slug?.startsWith('page:')) { 64 pages[f.slug.replace('page:', '')] = f.isEnabled; 65 } 66 } 67 } 68 } else { 69 // Default - don't hide anything if GraphQL not available 70 return; 71 } 72 73 // Hide links for pages that are disabled and have show_in_nav = false 74 footer.querySelectorAll('a[data-page]').forEach(link => { 75 const page = link.dataset.page; 76 if (pages[page] === false) { 77 const featureKey = `page:${page}`; 78 const state = hiddenStates[featureKey]; 79 if (state && state.show_in_nav === false) { 80 link.closest('li').style.display = 'none'; 81 } 82 } 83 }); 84 85 // Hide empty columns (where all links are hidden) 86 footer.querySelectorAll('.footer-column').forEach(col => { 87 const visibleLinks = col.querySelectorAll('li:not([style*="display: none"])'); 88 if (visibleLinks.length === 0) { 89 col.style.display = 'none'; 90 } 91 }); 92 } catch (e) { 93 console.warn('[Footer] Failed to load features:', e); 94 } 95 } 96 97 // Run after a short delay to ensure API is ready 98 if (document.readyState === 'loading') { 99 document.addEventListener('DOMContentLoaded', () => setTimeout(updateFooterVisibility, 100)); 100 } else { 101 setTimeout(updateFooterVisibility, 100); 102 } 103})();
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.