1document.addEventListener("DOMContentLoaded", function () { 2 const tag_battery_level = document.querySelector('span#battery_level'); 3 if (tag_battery_level && navigator.getBattery) { 4 setInterval(function () { 5 navigator.getBattery().then(battery => { 6 const battery_level = Math.round(battery.level * 100); 7 tag_battery_level.innerHTML = `${battery_level}% ${battery.charging ? 'charging' : 'discharging'}`; 8 }); 9 }, 10000); 10 } 11 12 fetch("/api/visitor-count") 13 .then(response => response.json()) 14 .then(data => { 15 if (data.success) { 16 document.getElementById("visitorToday").textContent = data.visitors.todayVisitors; 17 document.getElementById("visitorTotal").textContent = data.visitors.totalVisitors; 18 } 19 }) 20 .catch(error => console.error("Error fetching visitor count:", error)); 21 22 const currentDate = new Date(); 23 const months = ["January", "February", "March", "April", "May", "June", "July",
24 "August", "September", "October", "November", "December"]; 25 const dateElement = document.getElementById("jadwaltime"); 26 if (dateElement) { 27 dateElement.textContent = `${months[currentDate.getMonth()]} ${currentDate.getDate()} ${currentDate.getFullYear()}`; 28 } 29 30 function updateTime() { 31 const now = new Date(); 32 const hours = now.getHours(); 33 const timeString = `${String(hours).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}`; 34 35 let greeting; 36 if (hours < 4) greeting = "Good Night"; 37 else if (hours < 12) greeting = "Good Morning"; 38 else if (hours < 16) greeting = "Good Afternoon"; 39 else if (hours < 20) greeting = "Good Evening"; 40 else greeting = "Good Night"; 41 42 const timeElement = document.getElementById("row-no-guttersalign-items-center"); 43 const greetingElement = document.getElementById("text-xsfont-weight-boldtext-uppercase-mb-1"); 44 45 if (timeElement) timeElement.textContent = timeStr
45ing; 46 if (greetingElement) greetingElement.textContent = greeting; 47 } 48 setInterval(updateTime, 1000); 49 updateTime(); 50 51 function initializeLikeButtons() { 52 document.querySelectorAll('a.collapse-item[href^="/api/"]').forEach(link => { 53 const apiUrl = new URL(link.href, window.location.origin).pathname; 54 let apiName = apiUrl.replace('/api/', '').replace(/\//g, '-').trim(); 55 56 if (!apiName) return; 57 58 const oldLikeContainer = link.querySelector('.like-container'); 59 if (oldLikeContainer) oldLikeContainer.remove(); 60 61 const likeContainer = document.createElement("span"); 62 likeContainer.className = "like-container"; 63 likeContainer.style.display = "inline-flex"; 64 likeContainer.style.alignItems = "center"; 65 likeContainer.style.marginLeft = "10px"; 66 67 const likeButton = document.createElement("button"); 68 likeButton.className = "like-button"; 69 likeButton.style.background = "transparent"; 70 likeButton.style.border = "none"; 71 likeButton.style.outline = "none"; // Remove focus border 72 likeButton.style.cursor = "pointer"; 73 likeButton.style.fontSize = "18px"; // Decreased size 74 likeButton.style.padding = "3px"; 75 76 const likeIcon = document.createElement("i"); 77 likeIcon.className = "far fa-heart like-icon"; 78 likeIcon.setAttribute("data-api", apiName); 79 likeIcon.style.pointerEvents = "none"; 80 81 likeButton.appendChild(likeIcon); 82 83 const likeCount = document.createElement("span"); 84 likeCount.className = "like-count"; 85 likeCount.id = `likeCount-${apiName}`; 86 likeCount.style.marginLeft = "5px"; 87 likeCount.style.fontSize = "14px"; 88 likeCount.textContent = "0"; 89 90 likeContainer.append(likeButton, likeCount); 91 link.append(" ", likeContainer); 92 93 // Fetch like status & count 94 fetch(`/api/likes?api=${encodeURIComponent(apiName)}`) 95 .then(response => response.json()) 96 .then(data => { 97 if (data) { 98 likeCount.textContent = data.likes; 99 100 // If user has liked before (based on IP), show as liked 101 if (data.liked) { 102 likeIcon.classList.replace("far", "fas"); 103 likeIcon.classList.add("text-danger"); 104 } 105 } 106 }) 107 .catch(error => console.error(`Error fetching likes for ${apiName}:`, error)); 108 }); 109 } 110 111 initializeLikeButtons(); 112 113 // Like/unlike button click event 114 document.addEventListener("click", function (event) { 115 const likeButton = event.target.closest(".like-button"); 116 if (!likeButton) return; 117 118 event.preventDefault(); 119 const likeIcon = likeButton.querySelector(".like-icon"); 120 const apiName = likeIcon.getAttribute("data-api"); 121 if (!apiName) return; 122 123 const isLiked = likeIcon.classList.contains("fas"); 124 const url = isLiked ? "/api/unlike" : "/api/like"; 125 const likeCountElement = document.getElementById(`likeCount-${apiName}`); 126 127 let currentLikes = parseInt(likeCountElement.textContent) || 0; 128 129 // Optimistic UI update 130 likeCountElement.textContent = isLiked ? currentLikes - 1 : currentLikes + 1; 131 likeIcon.classList.toggle("far", isLiked); 132 likeIcon.classList.toggle("fas", !isLiked); 133 likeIcon.classList.toggle("text-danger", !isLiked); 134 135 // Send request to backend 136 fetch(url, { 137 method: "POST", 138 headers: { "Content-Type": "application/json" }, 139 body: JSON.stringify({ api: apiName }) 140 }) 141 .then(response => response.json()) 142 .then(data => { 143 if (data.likes !== undefined) { 144 likeCountElement.textContent = data.likes; 145 } 146 }) 147 .catch(error => console.error(`Error updating like for ${apiName}:`, error)); 148 }); 149});
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.