1 2 3 4// 546040425 5document.addEventListener('DOMContentLoaded', (event) => { 6 7 // Namaz Timings API 8 9 const islamicDateTodayTxt = document.getElementById("islamicDateTodayTxt"); 10 const gregorianDateTodayTxt = document.getElementById("gregorianDateTodayTxt"); 11 12 const fajrTimeTxt = document.getElementById("fajrTimeTxt"); 13 const sunriseTimeTxt = document.getElementById("sunriseTimeTxt"); 14 const sunsetTimeTxt = document.getElementById("sunsetTimeTxt"); 15 const zuhr = document.getElementById("dhuhrTimeTxt"); 16 const asarTimeTxt = document.getElementById("asarTimeTxt"); 17 const maghribTimeTxt = document.getElementById("maghribTimeTxt"); 18 const ishaTimeTxt = document.getElementById("ishaTimeTxt"); 19 const currentLocationTxt = document.getElementById("currentLocationTxt"); 20 const changeLocationLoadOverlay = document.getElementById("changeLocationLoadOverlay"); 21 const upcomingPrayerNameTxt = document.getElementById("upcomingPrayerNameTxt"); 22 const upcomingPrayerTimeTxt = document.getElementById("upcomingPrayerTimeTxt"); 23 24 let countdownInterval; 25 26 27 28 const runPrayerTimeApi = (cityName, countryName) => { 29 changeLocationLoadOverlay.style.display = "block"; 30 // console.log("API Requesting...") 31 // Get current date 32 const currentDate = new Date(); 33 const day = String(currentDate.getDate()).padStart(2, '0');
34 const month = String(currentDate.getMonth() + 1).padStart(2, '0'); // Months are zero-based 35 const year = currentDate.getFullYear(); 36 const formattedDate = `${day}-${month}-${year}`; 37 38 const calculationMethod = localStorage.getItem("calculationMethod"); 39 if (calculationMethod) { 40 changeMethodInput.value = calculationMethod; 41 } else { 42 changeMethodInput.value = 1; // Default Method 43 currentMethodTxt.innerText = "University of Islamic Sciences, Karachi"; 44 localStorage.setItem("calculationMethod", "1"); 45 } 46 47 // Build the API URL with the current date 48 const apiUrl = `https://api.aladhan.com/v1/timingsByAddress/${formattedDate}?address=${encodeURIComponent(cityName)},${encodeURIComponent(countryName)}&method=${calculationMethod}`; 49 // console.log(apiUrl); 50 51 currentLocationTxt.innerText = `${cityName}, ${countryName}`; 52 53 fetch(apiUrl) 54 .then(response => { 55 if (!response.ok) { 56 throw new Error('Network response was not ok ' + response.statusText); 57 } 58 return response.json(); 59 }) 60 .then(data => { 61 // console.log('API data:', data); 62 63 // Extract the relevant data 64 const timings = data.data.timings; 65 const gregorianDate = data.data.date.gregorian; 66 const hijriDate = data.data.date.hijri; 67 68 // Format the dates 69 const formattedGregorianDate = `${parseInt(gregorianDate.day)} ${gregorianDate.month.en}, ${gregorianDate.year}`; 70 const formattedHijriDate = `${parseInt(hijriDate.day)} ${hijriDate.month.en}, ${hijriDate.year}`; 71 72 // Convert 24-hour time to 12-hour time with AM/PM 73 const convertTo12HourFormat = (time) => { 74 const [hour, minute] = time.split(':'); 75 const hourInt = parseInt(hour); 76 const period = hourInt >= 12 ? 'PM' : 'AM'; 77 const hour12 = hourInt % 12 || 12; // Convert hour to 12-hour format, 0 should be 12 78 return `${hour12}:${minute} ${period}`; 79 }; 80 81 // Set the text content of the elements 82 gregorianDateTodayTxt.textContent = formattedGregorianDate; 83 islamicDateTodayTxt.textContent = formattedHijriDate; 84 85 fajrTimeTxt.textContent = convertTo12HourFormat(timings.Fajr); 86 sunriseTimeTxt.textContent = convertTo12HourFormat(timings.Sunrise); 87 sunsetTimeTxt.textContent = convertTo12HourFormat(timings.Sunset); 88 dhuhrTimeTxt.textContent = convertTo12HourFormat(timings.Dhuhr); 89 asarTimeTxt.textContent = convertTo12HourFormat(timings.Asr); 90 maghribTimeTxt.textContent = convertTo12HourFormat(timings.Maghrib); 91 ishaTimeTxt.textContent = convertTo12HourFormat(timings.Isha); 92 93 changeLocationLoadOverlay.style.display = "none"; 94 95 try{ 96 updateUpcomingPrayer(timings); 97 } catch (error){ 98 console.log("Error Occured " + error) 99 } 100 101 102 103 }) 104 .catch(error => { 105 console.error('There has been a problem with your fetch operation:', error); 106 changeLocationLoadOverlay.style.display = "none"; 107 }); 108 109 110 } 111 112const updateUpcomingPrayer = (timings) => { 113const prayerTimes = [ 114 { name: 'Fajr', time: timings.Fajr }, 115 { name: 'Sunrise', time: timings.Sunrise }, 116 { name: 'Dhuhr', time: timings.Dhuhr }, 117 { name: 'Asr', time: timings.Asr }, 118 { name: 'Maghrib', time: timings.Maghrib }, 119 { name: 'Isha', time: timings.Isha } 120]; 121 122const now = new Date(); 123const nowHours = now.getHours(); 124const nowMinutes = now.getMinutes(); 125 126const currentTime = new Date(now.getFullYear(), now.getMonth(), now.getDate(), nowHours, nowMinutes); 127 128let nextPrayer; 129let nextPrayerTime; 130 131for (let i = 0; i < prayerTimes.length; i++) { 132 const [hours, minutes] = prayerTimes[i].time.split(':'); 133 const prayerTime = new Date(now.getFullYear(), now.getMonth(), now.getDate(), hours, minutes); 134 135 if (prayerTime > currentTime) { 136 nextPrayer = prayerTimes[i].name; 137 nextPrayerTime = prayerTime; 138 break; 139 } 140} 141 142if (!nextPrayer) { 143 const [hours, minutes] = prayerTimes[0].time.split(':'); 144 nextPrayer = prayerTimes[0].name; 145 nextPrayerTime = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, hours, minutes); 146} 147
148upcomingPrayerNameTxt.innerText = `${nextPrayer} in `; 149 150const updateCountdown = () => { 151 // console.log("RUnning asd") 152 const now = new Date(); 153 const diff = nextPrayerTime - now; 154 155 if (diff <= 0) { 156 runPrayerTimeApi(currentLocationTxt.innerText.split(',')[0], currentLocationTxt.innerText.split(',')[1].trim()); 157 return; 158 } 159 160 const hours = Math.floor(diff / 1000 / 60 / 60); 161 const minutes = Math.floor((diff / 1000 / 60) % 60); 162 const seconds = Math.floor((diff / 1000) % 60); 163 164 upcomingPrayerTimeTxt.innerText = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; 165}; 166 167updateCountdown(); 168clearInterval(countdownInterval); 169countdownInterval = setInterval(updateCountdown, 1000); 170}; 171 172 173 174function searchCountry(query, type, resultsElement) { 175 fetch(`/search-cities/?query=${query}&type=${type}`) 176 .then(response => response.json()) 177 .then(data => { 178 if (data.results) { 179 resultsElement.querySelector('ul').innerHTML = data.results.map(item => { 180 return `<li class="country-result-item">${item.country}</li>`; 181 }).join(''); 182 } 183 }) 184 .catch(error => console.error('Error:', error)); 185} 186 187function searchCity(query, type, countryName, resultsElement) { 188 fetch(`/search-cities/?query=${query}&type=${type}&country=${countryName}`) 189 .then(response => response.json()) 190 .then(data => { 191 if (data.results) { 192 resultsElement.querySelector('ul').innerHTML = data.results.map(item => { 193 return `<li class="city-result-item" data-city="${item.name}">${item.name}</li>`; 194 }).join(''); 195 } 196 }) 197 .catch(error => console.error('Error:', error)); 198} 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 const countryInput = document.getElementById("countryInput"); // Adjust the selector as per your input field 230 const countryResults = document.getElementById('countryResults'); 231 const countryCheckedIcon = document.getElementById('countryCheckedIcon'); 232 const cityInput = document.getElementById("cityInput"); // Adjust the selector as per your input field 233 const cityResults = document.getElementById('cityResults'); 234 const cityCheckedIcon = document.getElementById('cityCheckedIcon'); 235 const cityInputContainer = document.getElementById("cityInputContainer"); 236 const cityInputX = cityInputContainer.querySelector("input"); 237 const selectCountryTxt = document.getElementById("selectCountryTxt"); 238 const selectCityTxt = document.getElementById("selectCityTxt"); 239 const changeLocationBtn = document.getElementById("changeLocationBtn"); 240 const currentLocationBtn = document.getElementById("currentLocationBtn"); 241 const changeMethodBtn = document.getElementById("changeMethodBtn"); 242 const changeMethodInput = document.getElementById("changeMethodInput"); 243 244 let cityInputValid = false; 245 let countryInputValid = false; 246 let storedMethod = localStorage.getItem("calculationMethod"); 247 248 const currentMethodTxt = document.getElementById("currentMethodTxt"); 249 250 if (storedMethod && currentMethodTxt) { 251 for (const method of namazCalculationMethods) { 252 if (storedMethod == method.method_id) { 253 currentMethodTxt.innerText = method.name; 254 break; 255 } 256 } 257 } 258 259 260 261 262 changeMethodBtn.addEventListener("click", () => { 263 localStorage.setItem("calculationMethod", changeMethodInput.value); 264 const selectedMethodName = changeMethodInput.options[changeMethodInput.selectedIndex].text; 265 currentMethodTxt.innerText = selectedMethodName; 266 location.reload(); 267 }) 268 269 // Check if user location is in localStorage 270 let storedCity = localStorage.getItem('userLocationCity'); 271 let storedCountry = localStorage.getItem('userLocationCountry'); 272 273 if (storedCity == null){ 274 storedCity = userDefaultCity; 275 localStorage.setItem('userLocationCity', storedCity ); 276 } 277 cityInput.value = storedCity; 278 toggleIcon(cityInput, cityCheckedIcon, true); 279 cityInput.disabled = false;
280 cityInput.classList.remove("disabled-input"); 281 cityInputValid = true; 282 283 if (storedCountry == null){ 284 storedCountry = userDefaultCountry; 285 localStorage.setItem('userLocationCountry', storedCountry ); 286 } 287 countryInput.value = storedCountry; 288 toggleIcon(countryInput, countryCheckedIcon, true); 289 countryInputValid = true; 290 291 runPrayerTimeApi(storedCity, storedCountry); 292 293 changeLocationBtn.addEventListener("click", () => { 294 if (countryCheckedIcon.style.display != "block"){ 295 // console.log("Select Your Country ", countryCheckedIcon.style.display) 296 countryInputValidity(false); 297 } else if (cityCheckedIcon.style.display != "block"){ 298 // console.log("Select Your City") 299 cityInputValidity(false); 300 } else { 301 localStorage.setItem('userLocationCity', cityInput.value ); 302 localStorage.setItem('userLocationCountry', countryInput.value ); 303 304 const city = cityInput.value; 305 const country = countryInput.value; 306 // Location Changed Successfully 307 runPrayerTimeApi(cityInput.value, countryInput.value); 308 309 const modalElement = document.getElementById('changeLocationModal'); 310 const modal = bootstrap.Modal.getInstance(modalElement) || new bootstrap.Modal(modalElement); 311 modal.hide(); 312 313 // Todo 314 // 1 - Show Flash Message 315 } 316 }) 317 318 currentLocationBtn.addEventListener("click", () => { 319 localStorage.setItem('userLocationCity', userDefaultCity ); 320 localStorage.setItem('userLocationCountry', userDefaultCountry ); 321 322 location.reload() 323 }) 324 325 326 cityInputContainer.addEventListener("click", () => { 327 // console.log("clicked") 328 if (cityInput.disabled){ 329 // console.log("hshshsh") 330 countryInputValidity(false); 331 } else { 332 // console.log("Searching City") 333 countryInputValidity(true); 334 } 335 }) 336 337 338 const countryInputValidity = (value) => { 339 340 if (value){ 341 selectCountryTxt.style.display = "none"; 342 countryInput.classList.remove("invalid-input"); 343 } else { 344 selectCountryTxt.style.display = "block"; 345 countryInput.classList.add("invalid-input"); 346 } 347 } 348 349 const cityInputValidity = (value) => { 350 // console.log("City Validity ", value) 351 if (value){ 352 353 selectCityTxt.style.display = "none"; 354 cityInput.classList.remove("invalid-input"); 355 } else { 356 selectCityTxt.style.display = "block"; 357 cityInput.classList.add("invalid-input"); 358 } 359 } 360 361 362 363 // Function to show or hide the icon 364 function toggleIcon(inputElement, iconElement, valid) { 365 if (valid) { 366 iconElement.style.display = 'block'; 367 inputElement.classList.add("success-input"); 368 } else { 369 inputElement.classList.remove("success-input"); 370 iconElement.style.display = 'none'; 371 372 // Remove City Input if country is changed 373 if (inputElement == countryInput){ 374 cityInput.value = ""; 375 cityInput.classList.remove("success-input"); 376 cityCheckedIcon.style.display = 'none'; 377 } 378 } 379 } 380 381 const toggleCityInput = (valid) => { 382 valid = !valid; 383 if (valid) { 384 cityInput.classList.add("disabled-input"); 385 cityInput.disabled = true; 386 } else { 387 cityInput.classList.remove("disabled-input"); 388 cityInput.disabled = false; 389 } 390 } 391 392 const updateChangeBtnStatus = (inputType, valid) => { 393 394 if (inputType === "city"){ 395 if (valid){ 396 cityInputValid = true; 397 } else { 398 cityInputValid = false; 399 } 400 } else if (inputType === "country"){ 401 if (valid){ 402 countryInputValid = true; 403 } else { 404 countryInputValid = false; 405 } 406 } 407 408 409 if (countryInputValid && cityInputValid ){ 410 // console.log("From Is Valid") 411 changeLocationBtn.classList.remove("disabled-primary-btn"); 412 } else { 413 changeLocationBtn.classList.add("disabled-primary-btn"); 414 // console.log("Form not Valid") 415 } 416 } 417 418 419 420 // Function to check if the input matches the first result item 421 function isFirstItemMatchCountry(inputElement, resultsElement) { 422 updateChangeBtnStatus(); 423 const firstItem = resultsElement.querySelector('ul .country-result-item, ul .city-result-item'); 424 if (firstItem && inputElement.value.trim().toLowerCase() === firstItem.textContent.trim().toLowerCase()) { 425 toggleCityInput(true); 426 countryInputValidity(true); 427 // console.log("Contry Matched") 428 updateChangeBtnStatus("country", true); 429 return true; 430 } 431 432 // console.log("Country Falsed! input : ", inputElement.value.trim().toLowerCase(), ", first item is ", firstItem.textContent.trim().toLowerCase()) 433 toggleCityInput(false); 434 updateChangeBtnStatus("city", false); 435 return false;
436 } 437 438 function isFirstItemMatchCity(inputElement, resultsElement) { 439 440 const firstItem = resultsElement.querySelector('ul .country-result-item, ul .city-result-item'); 441 if (firstItem && inputElement.value.trim().toLowerCase() === firstItem.dataset.city.toLowerCase()) { 442 updateChangeBtnStatus("city", true); 443 cityInputValidity(true); 444 return true; 445 } else if (firstItem && inputElement.value.trim().toLowerCase() === firstItem.textContent.trim().toLowerCase()){ 446 updateChangeBtnStatus("city", true); 447 cityInputValidity(true); 448 return true; 449 } 450 updateChangeBtnStatus("city", false); 451 return false; 452 } 453 454 455 456 // Show country results when the input field is focused 457 countryInput.addEventListener('focus', () => { 458 if (countryInput.value.length > 0){ 459 countryResults.style.display = 'block'; 460 } 461 }); 462 463 // Show city results when the input field is focused 464 cityInput.addEventListener('focus', () => { 465 if (cityInput.value.length > 0){ 466 cityResults.style.display = 'block'; 467 } 468 }); 469 470 // Select the top item from the country results when Enter is pressed 471 countryInput.addEventListener('keydown', (event) => { 472 if (event.key === 'Enter') { 473 event.preventDefault(); // Prevent form submission if inside a form 474 const topItem = document.querySelector('#countryResults .country-result-item'); 475 if (topItem) { 476 countryInput.value = topItem.textContent; 477 countryResults.style.display = 'none'; 478 toggleIcon(countryInput, countryCheckedIcon, true); 479 } 480 } 481 }); 482 483 // Select the top item from the city results when Enter is pressed 484 cityInput.addEventListener('keydown', (event) => { 485 if (event.key === 'Enter') { 486 event.preventDefault(); // Prevent form submission if inside a form 487 const topItem = document.querySelector('#cityResults .city-result-item'); 488 if (topItem) { 489 cityInput.value = topItem.textContent; 490 cityResults.style.display = 'none'; 491 toggleIcon(cityInput, cityCheckedIcon, true); 492 } 493 } 494 }); 495 496 // Search for countries as the user types 497 countryInput.addEventListener('keyup', (event) => { 498 const query = event.target.value.trim(); 499 if (query.length > 0) { 500 searchCountry(query, 'country', countryResults); 501 countryResults.style.display = 'block'; 502 } else { 503 countryResults.style.display = 'none'; 504 toggleIcon(countryInput, countryCheckedIcon, false); 505 } 506 toggleIcon(countryInput, countryCheckedIcon, isFirstItemMatchCountry(countryInput, countryResults)); 507 }); 508 509 // Search for cities as the user types 510 cityInput.addEventListener('keyup', (event) => { 511 const query = event.target.value.trim(); 512 const countryName = countryInput.value.trim(); 513 if (query.length > 0) { 514 searchCity(query, 'city', countryName, cityResults); 515 cityResults.style.display = 'block'; 516 } else { 517 cityResults.style.display = 'none'; 518 toggleIcon(cityInput, cityCheckedIcon, false); 519 } 520 // console.log("trying to Check City") 521 toggleIcon(cityInput, cityCheckedIcon, isFirstItemMatchCity(cityInput, cityResults)); 522 }); 523 524 // Use event delegation to handle clicks on country result items 525 countryResults.addEventListener('click', (event) => { 526 if (event.target && event.target.matches('.country-result-item')) { 527 countryInput.value = event.target.textContent; 528 countryResults.style.display = 'none'; 529 isFirstItemMatchCountry(countryInput, countryResults); 530 toggleIcon(countryInput, countryCheckedIcon, true); 531 updateChangeBtnStatus("country", true); 532 } 533 }); 534 535 // Use event delegation to handle clicks on city result items 536 cityResults.addEventListener('click', (event) => { 537 if (event.target && event.target.matches('.city-result-item')) { 538 cityInput.value = event.target.textContent; 539 cityResults.style.display = 'none'; 540 toggleIcon(cityInput, cityCheckedIcon, true); 541 updateChangeBtnStatus("city", true); 542 } 543 }); 544 545 // Hide the country results when the input field loses focus 546 countryInput.addEventListener('blur', () => { 547 setTimeout(() => { 548 countryResults.style.display = 'none'; 549 }, 200); // Delay to allow click event to register 550 }); 551 552 // Hide the city results when the input field loses focus 553 cityInput.addEventListener('blur', () => { 554 setTimeout(() => { 555 cityResults.style.display = 'none'; 556 }, 200); // Delay to allow click event to register 557 }); 558 559 // Prevent the blur event when clicking on the results 560 countryResults.addEventListener('mousedown', (event) => { 561 event.preventDefault(); 562 }); 563 564 cityResults.addEventListener('mousedown', (event) => { 565 event.preventDefault(); 566 }); 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581}); 582
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.