PageSourceSearch

https://sitinshade.com/index.js

js sitinshade.com collected 2026-10-03 19:46:54 UTC 24,309 bytes, 739 lines download raw bytes

1window.addEventListener("DOMContentLoaded", function () {
2  window.addEventListener("offline", function () {
3    const container = document.querySelector(".container");
4    container.innerHTML =
5      '<H1>NO INTERNET</H1>';
6  });
7  if (!navigator.onLine) {
8    const container = document.querySelector(".container");
9    container.innerHTML = '<h1>NO INTERNET</h1>    <button id="refresh-button" onClick="refreshPage()" class="buttoncurrent ghost tiempo">Refresh Page</button>';
10  }
11
12
13  let sourceMarker;
14  let destinationMarker;
15  var sourceIcon = L.icon({
16    iconUrl: "source.png",
17    iconSize: [32, 32],
18  });
19  var destinationIcon = L.icon({
20    iconUrl: "destination.png",
21    iconSize: [32, 32],
22  });
23
24  fetchCurrentTime();
25  setupAutocomplete("source", { delay: 500 });
26  setupAutocomplete("destination", { delay: 500 });
27
28  const map = initializeMap();
29
30  var myAttrControl = L.control.attribution().addTo(map);
31  myAttrControl.setPrefix('<a href="https://leafletjs.com/">Leaflet</a>');
32
33  const fetchpage = sessionStorage.getItem("fetchpage");
34  console.log(fetchpage);
35
36  if (fetchpage == "true") {
37
38
39    const sourceLocation = sessionStorage.getItem("sourceLocation");
40    const destinationLocation = sessionStorage.getItem("destinationLocation");
41    const date = sessionStorage.getItem("date");
42    const time = sessionStorage.getItem("time");
43
44    // Retrieve the saved marker coordinates
45    const sourceMarkerLat = sessionStorage.getItem("sourceMarkerLat");
46    const sourceMarkerLng = sessionStorage.getItem("sourceMarkerLng");
47    const destMarkerLat = sessionStorage.getItem("destMarkerLat");
48    const destMarkerLng = sessionStorage.getItem("destMarkerLng");
49
50    if (sourceLocation) {
51      document.getElementById("source").value = sourceLocation;
52    }
53    if (destinationLocation) {
54      document.getElementById("destination").value = destinationLocation;
55    }
56    if (date) {
57      document.getElementById("date").value = date;
58    }
59    if (time) {
60      document.getElementById("time").value = time;
61    }
62    if (sourceMarkerLat && sourceMarkerLng) {
63      sourceMarker = L.marker([parseFloat(sourceMarkerLat), parseFloat(sourceMarkerLng)], {
64        title: sourceLocation,
65        draggable: true,
66        icon: sourceIcon,
67      });
68      sourceMarker.addTo(map).bindPopup(sourceLocation);
69    }
70    if (destMarkerLat && destMarkerLng) {
71      destinationMarker = L.marker([parseFloat(destMarkerLat), parseFloat(destMarkerLng)], {
72        title: destinationLocation,
73        draggable: true,
74        icon: destinationIcon,
75      });
76      destinationMarker.addTo(map).bindPopup(destinationLocation);
77    }
78  }
79
80  document
81    .getElementById("submit-button")
82    .addEventListener("click", async function () {
83
84      const sourceLocation = document.getElementById("source").value;
85      const destinationLocation = document.getElementById("destination").value;
86      const date = document.getElementById("date").value;
87      const time = document.getElementById("time").value;
88
89
90      sessionStorage.setItem("sourceLocation", sourceLocation);
91      sessionStorage.setItem("destinationLocation", destinationLocation);
92      sessionStorage.setItem("date", date);
93      sessionStorage.setItem("time", time);
94
95
96      sessionStorage.setItem("sourceMarkerLat", sourceMarker.getLatLng().lat);
97      sessionStorage.setItem("sourceMarkerLng", sourceMarker.getLatLng().lng);
98
99      sessionStorage.setItem("destMarkerLat", destinationMarker.getLatLng().lat);
100      sessionStorage.setItem("destMarkerLng", destinationMarker.getLatLng().lng);
101
102
103
104      sessionStorage.setItem("fetchpage", false);
105
106      const sourceMarkerCoords = sourceMarker
107        ? sourceMarker.getLatLng()
108        : await geocodeAddress(document.getElementById("source").value);
109      const destMarkerCoords = destinationMarker
110        ? destinationMarker.getLatLng()
111        : await geocodeAddress(document.getElementById("destination").value);
112
113      if (sourceMarkerCoords && destMarkerCoords) {
114        initRouting(sourceMarkerCoords, destMarkerCoords);
115        const container = document.querySelector(".container");
116        container.innerHTML =
117          '<div class="spinner"> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> </div>';
118      }
119    });
120    function setupAutocomplete(inputId, options) {
121      const inputElement = document.getElementById(inputId);
122    
123      new Autocomplete(inputId, {
124        delay: options.delay ,
125        selectFirst: options.selectFirst || true,
126        howManyCharacters: options.howManyCharacters || 2,
127    
128        onSearch: function ({ currentValue }) {
129          const photonApi = `https://photon.komoot.io/api/?q=${encodeURI(currentValue)}&limit=5`;
130          const nominatimApi = `https://nominatim.openstreetmap.org/search?format=geojson&limit=5&q=${encodeURI(currentValue)}`;
131    
132          return new Promise((resolve) => {
133            fetch(photonApi)
134              .then((response) => response.json())
135              .then((data) => {
136                if (data.features && data.features.length > 0) {
137                  // Transform Photon results to match the expected format
138                  const transformedFeatures = data.features.map(feature => ({
139                    type: "Feature",
140                    geometry: feature.geometry,
141                    properties: {
142                      ...feature.properties,
143                      display_name: [
144                        feature.properties.name,
145                        feature.properties.state,
146                        feature.properties.country
147                      ].filter(Boolean).join(', ')
148                    }
149                  }));
150                  resolve(transformedFeatures);
151                } else {
152                  // If Photon returns no results, fall back to Nominatim
153                  return fetch(nominatimApi);
154                }
155              })
156              .then((response) => response ? response.json() : null)
157              .then((data) => {
158                if (data && data.features) {
159                  resolve(data.features);
160                } else {
161                  resolve([]);
162                }
163              })
164              .catch((error) => {
165                console.error(error);
166                resolve([]);
167              });
168          });
169        },
170    
171        onResults: ({ currentValue, matches, template }) => {
172          const regex = new RegExp(currentValue, "i");
173          return matches === 0
174            ? template
175            : matches
176              .map((element) => {
177                return `
178                  <li class="loupe" role="option">
179                    ${element.properties.display_name.replace(regex, (str) => `<b>${str}</b>`)}
180                  </li> `;
181              })
182              .join("");
183        },
184    
185        onSubmit: ({ object }) => {
186          const displayName = object.properties.display_name;
187          const cord = object.geometry.coordinates;
188          const customId = Math.random();
189    
190          if (inputId === "source") {
191            if (sourceMarker) {
192              map.removeLayer(sourceMarker);
193            }
194    
195            sourceMarker = L.marker([cord[1], cord[0]], {
196              title: displayName,
197              id: customId,
198              draggable: true,
199              icon: sourceIcon,
200            });
201            sourceMarker.addTo(map).bindPopup(displayName);
202          } else if (inputId === "destination") {
203            if (destinationMarker) {
204              map.removeLayer(destinationMarker);
205            }
206            destinationMarker = L.marker([cord[1], cord[0]], {
207              title: displayName,
208              id: customId,
209              draggable: true,
210              icon: destinationIcon,
211            });
212            destinationMarker.addTo(map).bindPopup(displayName);
213          }
214          map.panTo([cord[1], cord[0]]);
215    
216          inputElement.value = displayName;
217        },
218    
219        onSelectedItem: ({ index, element, object }) => {
220          // console.log("onSelectedItem:", index, element, object);
221        },
222    
223        noResults: ({ currentValue, template }) =>
224          template(`<li>No results found: "${currentValue}"</li>`),
225      });
226    }
227
228  function initializeMap() {
229    const config = {
230      minZoom: 7,
231      maxZoom: 18,
232    };
233
234    const zoom = 15;
235    const lat = 52.23397;
236    const lng = 21.01489;
237
238    const map = L.map("map", { attributionControl: false }
238).setView([lat, lng], zoom);
239
240    L.tileLayer(
241      // "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
242      "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png?key=cb1_3vel_1_12acf6fb072e7b9124c21e4f",
243      {
244        attribution:
245          'Created by <a href="https://amithv.xyz">amithv.xyz</a> &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, &copy; <a href="https://carto.com/attributions">CARTO</a> ',
246      }
247    ).addTo(map);
248
249    return map;
250  }
251
252  async function initRouting(sourceLatLng, destLatLng) {
253    const date = document.getElementById("date").value;
254    const time = document.getElementById("time").value;
255    const timezone = document.getElementById("timezone").value;
256    var hours = parseInt(document.getElementById('hour-input').value);
257    var minutes = parseInt(document.getElementById('min-input').value);
258
259    // Calculate the total duration in minutes
260    console.log(hours, minutes);
261    let duration = (isNaN(hours) ? 0 : hours * 3600) + (isNaN(minutes) ? 0 : minutes * 60);
262    if (Number.isNaN(duration))
263      duration = 0;
264
265    result = await callSunlightAPI(
266      sourceLatLng,
267      destLatLng,
268      date,
269      time,
270      timezone,
271      duration
272    );
273    if (!result) {
274      container = document.querySelector(".container");
275      container.innerHTML = `<div style="color: #fff">No route exist</div> <button id="refresh-button" onClick="refreshPage()" class="buttoncurrent ghost tiempo">Refresh Page</button>`;
276      return;
277    }
278
279    resultRouting = await getcoodrinates(
280      sourceLatLng.lat,
281      sourceLatLng.lng,
282      destLatLng.lat,
283      destLatLng.lng
284    );
285    var polyLine = L.multiOptionsPolyline(resultRouting, {
286      multiOptions: {
287        optionIdxFn: function (latLng, prevLatLng, index, allLatlngs) {
288          return result.segments[index] + 1;
289        },
290        options: [
291          {
292            color: "#FFA500",
293            weight: 6,
294
295          },
296          {
297            color: "grey",
298            weight: 6,
299
300          },
301          {
302            color: "#4A90E2",
303            weight: 6,
304            stroke: true,
305
306          },
307        ],
308      },
309      weight: 3,
310    }).addTo(map);
311
312    var bounds = L.latLngBounds(
313      L.latLng(sourceLatLng.lat, sourceLatLng.lng),
314      L.latLng(destLatLng.lat, destLatLng.lng)
315    );
316
317    map.flyToBounds(bounds, { duration: 3 });
318
319    // routingControl.route();
320  }
321
322  async function geocodeAddress(address) {
323    const api = `https://nominatim.openstreetmap.org/search?format=json&limit=1&q=${encodeURI(
324      address
325    )}`;
326
327    try {
328      const response = await fetch(api);
329      const data = await response.json();
330
331      if (data.length > 0) {
332        const latlng = L.latLng(data[0].lat, data[0].lon);
333        return latlng;
334      } else {
335        console.error(`Geocoding failed for address: ${address}`);
336        return null;
337      }
338    } catch (error) {
339      console.error(error);
340      return null;
341    }
342  }
343
344  async function callSunlightAPI(
345    sourceLatLng,
346    destLatLng,
347    date,
348    time,
349    timezone,
350    duration
351  ) {
352    const apiURL = `https://sun.amithv.workers.dev/?lat1=${sourceLatLng.lat}&lon1=${sourceLatLng.lng}&lat2=${destLatLng.lat}&lon2=${destLatLng.lng}&date=${date}&time=${time}&tz=${timezone}&duration=${duration}`;
353
354    const container = document.querySelector(".container");
355    container.innerHTML =
356      '<div class="spinner"> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> </div>';
357    let segments;
358
359    await fetch(apiURL)
360      .then((response) => response.json())
361      .then(async (data) => {
362        if (data) {
363          if (Object.keys(data).length === 0) {
364            container.innerHTML = `<div style="color: #fff">An error occurred while loading data.</div> <button id="refresh-button" onClick="refreshPage()" class="buttoncurrent ghost tiempo">Refresh Page</button>`;
365            return;
366          }
367          segments = data;
368          // console.log(segments);
369          let preferredSeat = "";
370          if (data.leftPercentage >
370 data.rightPercentage) {
371            preferredSeat = "Right Side";
372          } else if (data.leftPercentage < data.rightPercentage) {
373            preferredSeat = "Left Side";
374          } else {
375            preferredSeat = "No Preference";
376          }
377          container.innerHTML = `
378  
379            <div style="background-color:rgba(0,0,0,0.2);color: #fff; padding: 20px; font-family:'Lucida Grande',monospace; font-size: 18px;font-weight: bold;">
380            <div style="font-size: 20px; font-weight: bold;">Preferred Seating :<span style="color:#FF5733"> ${preferredSeat}</span></div>
381            <div style="margin-top: 10px;">
382            <div style="font-size: 16px;color:White;"><span style="font-size: 20px;">${formatDistance(
383            data.distance
384          )} / ${formatDistanceToMiles(data.distance)} :${secondsToReadableTime(data.duration)}</span></div>
385
386                <h4>Sun Exposure Data</h4>
387                <b>
388                <div style="font-size: 16px;color:#FFA500;">Sun Left: <span style="font-size: 20px;">${data.leftPercentage
389            }%</span></div>
390                <div style="font-size: 16px;color:#4A90E2;">Sun Right: <span style="font-size: 20px;">${data.rightPercentage
391            }%</span></div>
392                <div style="font-size: 16px;color:grey;">No Sun: <span style="font-size: 20px;">${data.noSunPercentage
393            }%</span></div>
394                </b>
395            </div>
396            <button id="refresh-button" onClick="newLocation()" class="buttoncurrent ghost tiempo">New Location</button>
397            <button id="load-previous-button" onClick="EditPage()" class="buttoncurrent ghost tiempo">Edit Search</button>
398
399        </div>`;
400        }
401      })
402      .catch((error) => {
403        segments = null;
404        console.error("Error calling sunlight API:", error);
405        container.innerHTML = `<div style="color: #fff">An error occurred while loading data.</div> <button id="refresh-button" onClick="refreshPage()" class="buttoncurrent ghost tiempo">Refresh Page</button>`;
406      });
407    return segments;
408  }
409
410  document
411    .getElementById("current-time-button")
412    .addEventListener("click", async function () {
413      fetchCurrentTime()
414
415    })
416
417  document
418    .getElementById("current-location-button")
419    .addEventListener("click", async function () {
420      try {
421        // Get the user's current location using the Geolocation API
422        const position = await getCurrentLocation();
423
424        // Update the source input field with the current location's address (optional)
425        const currentLocationAddress = await reverseGeocode(
426          position.coords.latitude,
427          position.coords.longitude
428        );
429        if (currentLocationAddress) {
430          document.getElementById("source").value = currentLocationAddress;
431        }
432
433        // Update the sourceMarker on the map
434        if (sourceMarker) {
435          map.removeLayer(sourceMarker);
436        }
437        sourceMarker = L.marker(
438          [position.coords.latitude, position.coords.longitude],
439          {
440            title: "Current Location",
441            icon: sourceIcon,
442          }
443        );
444        sourceMarker.addTo(map).bindPopup("Current Location");
445        map.panTo([position.coords.latitude, position.coords.longitude]);
446      } catch (error) {
447        console.error("Error getting current location:", error);
448      }
449    });
450  map.on("click", function (e) {
451    if (!sourceMarker) {
452      sourceMarker = L.marker(e.latlng, {
453        draggable: true,
454        icon: sourceIcon,
455      }).addTo(map);
456      sourceMarker.on("dragend", function (e) {
457        // Get the new marker position
458        const newPosition = e.target.getLatLng();
459        // Do something with the new position, such as update the route
460      });
461    } else if (!destinationMarker) {
462      destinationMarker = L.marker(e.latlng, {
463        draggable: true,
464        icon: destinationIcon,
465      }).addTo(map);
466      destinationMarker.on("dragend", function (e) {
467        // Get the new marker position
468        const newPosition = e.target.getLatLng();
469        // Do something with the new position, such as update the route
470      });
471      // Perform any necessary actions here, such as calculating the route between the markers
472    }
473  });
474
475
476  let hourInput = document.getElementById('hour-input');
477  let minInput = document.getElementById('min-input');
478  let checkboxInput = document.getElementById('checkboxInput');
479
480  hourInput.addEventListener('input', function() {
481    if (this.value !== '' || minInput.value !== '') {
482      checkboxInput.checked = false;
483      this.setCustomValidity('');
484      minInput.setCustomValidity('');
485    } else {
486      checkboxInput.checked = true;
487    }
488  });
489  
490  minInput.addEventListener('input', function() {
491    if (this.value !== '' || hourInput.value !== '') {
492      checkboxInput.checked = false;
493      this.setCustomValidity('');
494      hourInput.setCustomValidity('');
495    } else {
496      checkboxInput.checked = true;
497    }
498  });
499
500  checkboxInput.addEventListener('click', function() {
501    hourInput.value = '';
502    minInput.value = '';
503    if (!this.checked) {
504      hourInput.setCustomValidity('Please enter the duration.');
505      minInput.setCustomValidity('Please enter the duration.');
506      hourInput.reportValidity();
507      hourInput.focus();
508    } else {
509      hourInput.setCustomValidity('');
510      minInput.setCustomValidity('');
511    }
512  });
513});
514
515
516function EditPage() {
517  sessionStorage.setItem("fetchpage", true);
518  refreshPage();
519
520};
521
522
523function fetchCurrentTime() {
524  const today = new Date();
525  const currentDate = today.toISOString().split("T")[0];
526  document.getElementById("date").value = currentDate;
527
528  const time = today.toLocaleTimeString(navigator.language, {
529    hour: "2-digit",
530    minute: "2-digit",
531    hour12: false, // Force 24-hour format
532
533  });
534  document.getElementById("time").value = time;
535
536  const offsetInMinutes = today.getTimezoneOffset();
537  const hours = Math.floor(Math.abs(offsetInMinutes) / 60);
538  const minutes = Math.abs(offsetInMinutes) % 60;
539  const sign = offsetInMinutes > 0 ? "-" : "";
540  const offsetDecimal = hours + minutes / 60;
541  const timezone = `${sign}${offsetDecimal}`;
542  document.getElementById("timezone").value = timezone;
543}
544
545function getCurrentLocation() {
546  return new Promise((resolve, reject) => {
547    if ("geolocation" in navigator) {
548      navigator.geolocation.getCurrentPosition(resolve, reject);
549    } else {
550      reject("Geolocation is not available in this browser.");
551    }
552  });
553}
554async function reverseGeocode(latitude, longitude) {
555  const api = `https://nominatim.openstreetmap.org/reverse?format=json&lat=${latitude}&lon=${longitude}`;
556  try {
557    const response = await fetch(api);
558    const data = await response.json();
559    if (data.display_name) {
560      return data.display_name;
561    } else {
562      console.error("Geocoding response did not contain a valid address.");
563      return null;
564    }
565  } catch (error) {
566    console.error("Error during reverse geocoding:", error);
567    return null;
568  }
569}
570
571async function getcoodrinates(lat1, lon1, lat2, lon2) {
572  const osrmApiUrl = `https://routing.openstreetmap.de/routed-car/route/v1/driving/${lon1},${lat1};${lon2},${lat2}?overview=full&geometries=geojson`;
573
574  try {
575    const response = await fetch(osrmApiUrl);
576    const routedata = await response.json();
577
578    if (routedata) {
579      const route = routedata.routes[0];
580      const segments = route.geometry.coordinates.map((coordinate) => {
581        return {
582          lat: coordinate[1],
583          lng: coordinate[0],
584        };
585      });
586      return segments;
587    }
588  } catch (error) {
589    console.error("Error during reverse geocoding:", error);
590    return null;
591  }
592}
593function secondsToReadableTime(seconds) {
594  var seconds = parseInt(seconds, 10);
595  var hours = Math.floor(seconds / 3600);
596  var minutes = Math.floor((seconds - hours * 3600) / 60);
597  var seconds = seconds - hours * 3600 - minutes * 60;
598  if (!!hours) {
599    if (!!minutes) {
600      return `${hours}h ${minutes}m ${seconds}s`;
601    } else {
602      return `${hours}h ${seconds}s`;
603    }
604  }
605  if (!!minutes) {
606    return `${minutes}m ${seconds}s`;
607  }
608  return `${seconds}s`;
609}
610function formatDistance(meters) {
611  if (meters >= 1000) {
612    return Math.round(meters / 1000.0) + " km";
613  } else if (meters >= 100) {
614    return Math.round(meters) + " m";
615  } else {
616    return meters.toFixed(1) + " m";
617  }
618}
619function formatDistanceToMiles(meters) {
620  const metersToMiles = 0.000621371; // 1 meter is approximately 0.000621371 miles
621
622  const miles = meters * metersToMiles;
623
624  if (miles >= 1) {
625    return miles.toFixed(2) + " miles";
626  } else {
627    return (miles * 5280).toFixed(2) + " feet"; // Convert to feet if less than a mile
628  }
629}
630
631if ("serviceWorker" in navigator) {
632  // register service worker
633  navigator.serviceWorker.register("service-worker.js");
634}
635// if ("serviceWorker" in navigator) {
636//   // register service worker
637//   navigator.serviceWorker.register("sw.js");
638// }
639
640function refreshPage() {
641
642  window.location.reload();
643}
644function newLocation() {
645  sessionStorage.setItem("fetchpage", false);
646
647
648  refreshPage()
649}
650
651
652let defferedPrompt;
653const addbtn = document.querySelector('.installbtn');
654
655window.addEventListener('beforeinstallprompt', event => {
656  defferedPrompt = event
657  addbtn.style.display = 'block';
658});
659
660addbtn.addEventListener('click', event => {
661  defferedPrompt.prompt();
662
663  defferedPrompt.userChoice.then(choice => {
664    if (choice.outcome === 'accepted') {
665      console.log('user accepted the prompt')
666    }
667    defferedPrompt = null;
668  })
669})
670
671
672
673
674
675
676
677
678
679
680// form js 
681/* number selection*/
682document
683  .querySelectorAll(".writing :is(input , textarea)")
684  .forEach((writinginput) => {
685    writinginput.addEventListener("input", () => {
686      if (writinginput.value.trim() !== "") {
687        writinginput.classList.add("has-text");
688      } else {
689        writinginput.classList.remove("has-text");
690      }
691    });
692  });
693
694/* text area */
695document.querySelectorAll(".textarea textarea").forEach((textarea) => {
696  textarea.addEventListener("input", () => {
697    textarea.style.height = "1em";
698    const scrollHeight = textarea.scrollHeight;
699    textarea.style.height = `${scrollHeight}px`;
700  });
701});
702
703/* number input */
704
705function decrementValue(button) {
706  const input = button.nextElementSibling;
707  if (parseInt(input.value) > parseInt(input.min)) {
708    input.value = parseInt(input.value) - 1;
709  }
710}
711function incrementValue(button) {
712  const input = button.previousElementSibling;
713  if (input.value === "") {
714    input.value = parseInt(input.min);
715  } else if (parseInt(input.value) < parseInt(input.max)) {
716    input.value = parseInt(input.value) + 1;
717  }
718}
719
720
721
722
723
724// drop down menu
725function applyOpenStyle(selectElement) {
726  if (selectElement.classList.contains("select-open")) {
727    selectElement.classList.remove("select-open");
728  } else {
729    selectElement.classList.add("select-open");
730  }
731}
732function removeOpenStyle(selectElement) {
733  selectElement.classList.remove("select-open");
734}
735
736
737
738
739

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.