From aaa992a4c48ba7dff256f69d2478d98a7e157748 Mon Sep 17 00:00:00 2001 From: Prem Kumar <60751338+prem-k-r@users.noreply.github.com> Date: Sun, 26 Jan 2025 16:33:47 +0530 Subject: [PATCH] Code Split: Weather, UserText, browser-utils (#494) * Code Split * ID changed * fix browserUtils * minor changes * Update browser-utils.js Typo fix and isSafari more robust * Update ai-tools.js Reverted to avoid conflicts with #495 * Update index.html * Update script.js fix * Fix browser-utils.js * Update bookmarks.js * Update script.js * Update script.js * Update browser-utils.js final * Create background.js * Update manifest(firefox).json --- {docs => images}/Loading.png | Bin index.html | 17 +- manifest(firefox).json | 2 +- scripts/ai-tools.js | 8 +- scripts/background.js | 1 + scripts/backup-restore.js | 2 +- scripts/bookmarks.js | 16 +- scripts/browser-utils.js | 36 ++ scripts/clock.js | 3 +- scripts/custom-text.js | 58 +++ .../{google-app-menu.js => google-apps.js} | 5 +- scripts/languages.js | 2 +- scripts/preload.js | 10 +- scripts/script.js | 388 +----------------- scripts/voice-search.js | 2 +- scripts/wallpaper.js | 6 +- scripts/weather.js | 293 +++++++++++++ 17 files changed, 448 insertions(+), 401 deletions(-) rename {docs => images}/Loading.png (100%) create mode 100644 scripts/background.js create mode 100644 scripts/browser-utils.js create mode 100644 scripts/custom-text.js rename scripts/{google-app-menu.js => google-apps.js} (98%) create mode 100644 scripts/weather.js diff --git a/docs/Loading.png b/images/Loading.png similarity index 100% rename from docs/Loading.png rename to images/Loading.png diff --git a/index.html b/index.html index 4bb9cba4..139952b2 100644 --- a/index.html +++ b/index.html @@ -24,11 +24,14 @@ + + + - + @@ -59,7 +62,7 @@ - + @@ -601,7 +604,7 @@

View as

-
Humidity
+
@@ -616,7 +619,7 @@

View as

- Seems +
@@ -628,7 +631,7 @@

View as

- Earth +
@@ -845,10 +848,10 @@

View as

-
+
- diff --git a/manifest(firefox).json b/manifest(firefox).json index e8971292..8fb2d6b6 100644 --- a/manifest(firefox).json +++ b/manifest(firefox).json @@ -10,7 +10,7 @@ "https://search.brave.com/api/suggest*" ], "background": { - "scripts": ["background.js"], + "scripts": ["scripts/background.js"], "persistent": true }, "icons": { diff --git a/scripts/ai-tools.js b/scripts/ai-tools.js index 4c10e2f7..3e5fac67 100644 --- a/scripts/ai-tools.js +++ b/scripts/ai-tools.js @@ -6,7 +6,7 @@ * If not, see . */ -// when User click on "AI-Tools" +// When User click on "AI-Tools" const element = document.getElementById("toolsCont"); const shortcuts = document.getElementById("shortcutsContainer"); @@ -68,11 +68,9 @@ document.addEventListener("click", (event) => { } }); -document.getElementById("0NIHK").onclick = toggleShortcuts; - -// - +document.getElementById("aiToolsIcon").onclick = toggleShortcuts; +// Save and load checkbox state document.addEventListener("DOMContentLoaded", function () { const aiToolsCont = document.getElementById("aiToolsCont"); const aiToolsCheckbox = document.getElementById("aiToolsCheckbox"); diff --git a/scripts/background.js b/scripts/background.js new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/scripts/background.js @@ -0,0 +1 @@ + diff --git a/scripts/backup-restore.js b/scripts/backup-restore.js index c85e50af..1d06607f 100644 --- a/scripts/backup-restore.js +++ b/scripts/backup-restore.js @@ -189,4 +189,4 @@ resetbtn.addEventListener("click", () => { localStorage.clear(); location.reload(); } -}); +}); \ No newline at end of file diff --git a/scripts/bookmarks.js b/scripts/bookmarks.js index 3a79c947..723c7387 100644 --- a/scripts/bookmarks.js +++ b/scripts/bookmarks.js @@ -279,9 +279,9 @@ document.addEventListener("DOMContentLoaded", function () { // Open in a new tab event.preventDefault(); if (isFirefox) { - browser.tabs.create({url: node.url, active: false}); - } else if (isChrome) { - chrome.tabs.create({url: node.url, active: false}); + browser.tabs.create({ url: node.url, active: false }); + } else if (isChromiumBased) { + chrome.tabs.create({ url: node.url, active: false }); } else { window.open(node.url, "_blank"); } @@ -289,9 +289,9 @@ document.addEventListener("DOMContentLoaded", function () { // Open in the current tab event.preventDefault(); if (isFirefox) { - browser.tabs.update({url: node.url}); - } else if (isChrome) { - chrome.tabs.update({url: node.url}, function () { + browser.tabs.update({ url: node.url }); + } else if (isChromiumBased) { + chrome.tabs.update({ url: node.url }, function () { }); } else { window.location.href = node.url; @@ -312,6 +312,7 @@ document.addEventListener("DOMContentLoaded", function () { // ------------------------ End of Bookmark System ----------------------------------- +// Save and load the state of the bookmarks toggle document.addEventListener("DOMContentLoaded", function () { const bookmarksCheckbox = document.getElementById("bookmarksCheckbox"); const bookmarkGridCheckbox = document.getElementById("bookmarkGridCheckbox"); @@ -320,7 +321,7 @@ document.addEventListener("DOMContentLoaded", function () { let bookmarksPermission; if (isFirefox && browser.permissions) { bookmarksPermission = browser.permissions; - } else if (isChrome || isEdge || isBrave && chrome.permissions) { + } else if (isChromiumBased && chrome.permissions) { bookmarksPermission = chrome.permissions; } else { alert(translations[currentLanguage]?.UnsupportedBrowser || translations["en"].UnsupportedBrowser); @@ -380,6 +381,7 @@ document.addEventListener("DOMContentLoaded", function () { loadCheckboxState("bookmarkGridCheckboxState", bookmarkGridCheckbox); }) +// Keyboard shortcut for bookmarks document.addEventListener("keydown", function (event) { if (event.key === "ArrowRight" && event.target.tagName !== "INPUT" && event.target.tagName !== "TEXTAREA" && event.target.isContentEditable !== true) { if (bookmarksCheckbox.checked) { diff --git a/scripts/browser-utils.js b/scripts/browser-utils.js new file mode 100644 index 00000000..b3f124a9 --- /dev/null +++ b/scripts/browser-utils.js @@ -0,0 +1,36 @@ +/* + * Material You NewTab + * Copyright (c) 2023-2025 XengShi + * Licensed under the GNU General Public License v3.0 (GPL-3.0) + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + */ + +// Constants to detect the browser and platform details + +// Check if the browser is Firefox +const isFirefox = typeof browser !== "undefined" || navigator.userAgent.toLowerCase().includes("firefox"); + +// Check if the browser is Chromium-based +const isChromiumBased = !!window.chrome && (!!window.chrome.webstore || !!window.chrome.runtime) && !isFirefox; + +// Check if the browser is Edge +const isEdge = /Edg/.test(navigator.userAgent); + +// Check if the browser is Brave +const isBrave = !!(navigator.brave && navigator.brave.isBrave()); + +// Check if the browser is Opera +const isOpera = /OPR/.test(navigator.userAgent); + +// Check if the browser is Chrome +const isChrome = (/Chrome|CriOS/.test(navigator.userAgent)) && /Google Inc/.test(navigator.vendor) && !isEdge && !isBrave && !isOpera; + +// Check if the browser is Safari +const isSafari = /Safari/.test(navigator.userAgent) && !isChromiumBased && /Apple Computer/.test(navigator.vendor); + +// Check if the operating system is macOS +const isMac = /Macintosh|MacIntel|MacPPC|Mac68K/.test(navigator.platform); + +// Check if the device is a desktop (not mobile) +const isDesktop = !/Android|iPhone|iPad|iPod/.test(navigator.userAgent); diff --git a/scripts/clock.js b/scripts/clock.js index 6117d577..a146e2a3 100644 --- a/scripts/clock.js +++ b/scripts/clock.js @@ -318,6 +318,7 @@ document.addEventListener("DOMContentLoaded", function () { // ----------------------- End of clock display ------------------------- +// Save and load toggle state document.addEventListener("DOMContentLoaded", function () { const timeformatField = document.getElementById("timeformatField"); const hourcheckbox = document.getElementById("12hourcheckbox"); @@ -376,4 +377,4 @@ document.addEventListener("DOMContentLoaded", function () { loadCheckboxState("hourcheckboxState", hourcheckbox); loadActiveStatus("timeformatField", timeformatField); loadActiveStatus("greetingField", greetingField); -}); +}); \ No newline at end of file diff --git a/scripts/custom-text.js b/scripts/custom-text.js new file mode 100644 index 00000000..9ece7390 --- /dev/null +++ b/scripts/custom-text.js @@ -0,0 +1,58 @@ +/* + * Material You NewTab + * Copyright (c) 2023-2025 XengShi + * Licensed under the GNU General Public License v3.0 (GPL-3.0) + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + */ + +// Custom text +document.addEventListener("DOMContentLoaded", () => { + const userTextDiv = document.getElementById("userText"); + const userTextCheckbox = document.getElementById("userTextCheckbox"); + + // Load and apply the checkbox state + const isUserTextVisible = localStorage.getItem("userTextVisible") !== "false"; + userTextCheckbox.checked = isUserTextVisible; + userTextDiv.style.display = isUserTextVisible ? "block" : "none"; + + // Toggle userText display based on checkbox state + userTextCheckbox.addEventListener("change", () => { + const isVisible = userTextCheckbox.checked; + userTextDiv.style.display = isVisible ? "block" : "none"; + localStorage.setItem("userTextVisible", isVisible); + }); + + // Set the default language to English if no language is saved + const savedLang = localStorage.getItem("selectedLanguage") || "en"; + applyLanguage(savedLang); + + // Load the stored text if it exists + const storedValue = localStorage.getItem("userText"); + if (storedValue) { + userTextDiv.textContent = storedValue; + } else { + // Fallback to the placeholder based on the selected language + const placeholder = userTextDiv.dataset.placeholder || translations["en"].userText; // Fallback to English + userTextDiv.textContent = placeholder; + } + + // Handle input event + userTextDiv.addEventListener("input", function () { + localStorage.setItem("userText", userTextDiv.textContent); + }); + + // Remove placeholder text when the user starts editing + userTextDiv.addEventListener("focus", function () { + if (userTextDiv.textContent === userTextDiv.dataset.placeholder) { + userTextDiv.textContent = ""; // Clear the placeholder when focused + } + }); + + // Restore placeholder if the user leaves the div empty after editing + userTextDiv.addEventListener("blur", function () { + if (userTextDiv.textContent === "") { + userTextDiv.textContent = userTextDiv.dataset.placeholder; // Show the placeholder again if empty + } + }); +}); \ No newline at end of file diff --git a/scripts/google-app-menu.js b/scripts/google-apps.js similarity index 98% rename from scripts/google-app-menu.js rename to scripts/google-apps.js index 86db9337..a34177e2 100644 --- a/scripts/google-app-menu.js +++ b/scripts/google-apps.js @@ -39,8 +39,7 @@ document.addEventListener("click", function (event) { }); // ------------------------End of Google App Menu Setup----------------------------------- -// Toggle - +// Save and load toggle state document.addEventListener("DOMContentLoaded", function () { const googleAppsCont = document.getElementById("googleAppsCont"); @@ -56,4 +55,4 @@ document.addEventListener("DOMContentLoaded", function () { }); loadCheckboxState("googleAppsCheckboxState", googleAppsCheckbox); loadDisplayStatus("googleAppsDisplayStatus", googleAppsCont); -}); +}); \ No newline at end of file diff --git a/scripts/languages.js b/scripts/languages.js index 2be2fd7d..a8e2e409 100644 --- a/scripts/languages.js +++ b/scripts/languages.js @@ -9,7 +9,7 @@ // Translation data const translations = { en: en, // English - pt: pt, // Portuguese-BR + pt: pt, // Portuguese-BR (Brazil) zh: zh, // Chinese (Simplified) hi: hi, // Hindi hu: hu, // Hungarian diff --git a/scripts/preload.js b/scripts/preload.js index 200fcc64..d7f1030c 100644 --- a/scripts/preload.js +++ b/scripts/preload.js @@ -1,2 +1,10 @@ +/* + * Material You NewTab + * Copyright (c) 2023-2025 XengShi + * Licensed under the GNU General Public License v3.0 (GPL-3.0) + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + */ + // Set Loading Screen Color before Everything Loads -document.documentElement.style.setProperty('--Loading-Screen-Color',localStorage.getItem('LoadingScreenColor') || "#bbd6fd"); +document.documentElement.style.setProperty('--Loading-Screen-Color', localStorage.getItem('LoadingScreenColor') || "#bbd6fd"); diff --git a/scripts/script.js b/scripts/script.js index 5b3554e1..e455cc26 100644 --- a/scripts/script.js +++ b/scripts/script.js @@ -6,80 +6,31 @@ * If not, see . */ -// Function to detect which browser is being used -const isChrome = /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor); -const isFirefox = typeof browser !== "undefined"; -// const isFirefox = navigator.userAgent.toLowerCase().indexOf("firefox") > -1; -const isEdge = /Edg/.test(navigator.userAgent); -const isBrave = navigator.brave && navigator.brave.isBrave; // Detect Brave -const isDesktop = !/Android|iPhone|iPad|iPod/.test(navigator.userAgent); // Check if the device is not mobile - -let proxyurl; // TODO: Move all the CSS in a file called `theme/theme.css` (theme is the folder name) // TODO: Move all the SVG icons in files called `svgs/icon-name.svg` (svgs is the folder name, it already exists) -// TODO: Move all the to-do stuff in a file called `to-do.js` or `todo.js` or `todo-list.js` -// TODO: Move all the weather stuff in a file called `weather.js` // TODO: Move all the clock display stuff in a file called `clock-display.js` - can also be divided in two: `clock-default.js` and `clock-analog.js` -// TODO: Move all the voice search stuff in a file called `voice-search.js` // TODO: Move all the theme functions stuff in a file called `theme.js` -// TODO: Move all the BG Image stuff in a file called `background-images.js` // TODO: Move all the settings in a file called `settings.js` // TODO: Move all the search suggestions stuff in a file called `search-suggestions.js` // TODO: Move all the shortcut stuff in a file called `shortcut.js` (Difficult) -// TODO: Move into file called `browser-utils.js` with isChrome, isFirefox, etc. -// TODO: Move into file called `backup.js` or `backup-system.js` // TODO: Move into file called `welcome-greeting.js`(?) // TODO: Move into file called `animations.js`(?) -// TODO: @Migua-RC, can you move all the proxy stuff in a file called `proxy.js`? -window.addEventListener("DOMContentLoaded", async () => { - // Cache DOM elements - const userAPIInput = document.getElementById("userAPI"); - const userLocInput = document.getElementById("userLoc"); +let proxyurl; +window.addEventListener("DOMContentLoaded", () => { const userProxyInput = document.getElementById("userproxy"); - const saveAPIButton = document.getElementById("saveAPI"); - const saveLocButton = document.getElementById("saveLoc"); - const useGPSButton = document.getElementById("useGPS"); const saveProxyButton = document.getElementById("saveproxy"); - - // Load saved data from localStorage - const savedApiKey = localStorage.getItem("weatherApiKey"); - const savedLocation = localStorage.getItem("weatherLocation"); const savedProxy = localStorage.getItem("proxy"); - // Pre-fill input fields with saved data - if (savedLocation) userLocInput.value = savedLocation; - if (savedApiKey) userAPIInput.value = savedApiKey; - const defaultProxyURL = "https://mynt-proxy.rhythmcorehq.com"; //Default proxy url if (savedProxy && savedProxy !== defaultProxyURL) { userProxyInput.value = savedProxy; } - // Function to simulate button click on Enter key press - function handleEnterPress(event, buttonId) { - if (event.key === "Enter") { - document.getElementById(buttonId).click(); - } - } - - // Add event listeners for handling Enter key presses - userAPIInput.addEventListener("keydown", (event) => handleEnterPress(event, "saveAPI")); - userLocInput.addEventListener("keydown", (event) => handleEnterPress(event, "saveLoc")); userProxyInput.addEventListener("keydown", (event) => handleEnterPress(event, "saveproxy")); - // Save API key to localStorage - saveAPIButton.addEventListener("click", () => { - const apiKey = userAPIInput.value.trim(); - localStorage.setItem("weatherApiKey", apiKey); - userAPIInput.value = ""; - location.reload(); - }); - - const currentLanguage = getLanguageStatus("selectedLanguage") || "en"; - // Save the proxy to localStorage saveProxyButton.addEventListener("click", () => { let proxyurl = userProxyInput.value.trim(); @@ -105,292 +56,11 @@ window.addEventListener("DOMContentLoaded", async () => { location.reload(); }); - // Default Weather API key - const weatherApiKeys = [ - "d36ce712613d4f21a6083436240910", - "db0392b338114f208ee135134240312", - "de5f7396db034fa2bf3140033240312", - "c64591e716064800992140217240312", - "9b3204c5201b4b4d8a2140330240312", - "eb8a315c15214422b60140503240312", - "cd148ebb1b784212b74140622240312", - "7ae67e219af54df2840140801240312", - "0a6bc8a404224c8d89953341241912", - "f59e58d7735d4739ae953115241912" - ]; - const defaultApiKey = weatherApiKeys[Math.floor(Math.random() * weatherApiKeys.length)]; - - // Determine API key and proxy URL to use - const apiKey = savedApiKey || defaultApiKey; + // Determine which proxy URL to use proxyurl = savedProxy || defaultProxyURL; - - // Determine the location to use - let currentUserLocation = savedLocation; - - // Flag indicating whether to use GPS - const useGPS = JSON.parse(localStorage.getItem("useGPS")); - - // Fetch weather data based on a location - async function fetchWeather(location) { - const currentLanguage = getLanguageStatus("selectedLanguage") || "en"; - try { - let parsedData = JSON.parse(localStorage.getItem("weatherParsedData")); - const weatherParsedTime = parseInt(localStorage.getItem("weatherParsedTime")); - const weatherParsedLocation = localStorage.getItem("weatherParsedLocation"); - const weatherParsedLang = localStorage.getItem("weatherParsedLang"); - - const retentionTime = savedApiKey ? 120000 : 960000; // 2 min for user-entered API key, 16 min otherwise - - if (!parsedData || ((Date.now() - weatherParsedTime) > retentionTime) || (weatherParsedLocation !== currentUserLocation) || (weatherParsedLang !== currentLanguage)) { - // Fetch weather data using Weather API - let weatherApi = `https://api.weatherapi.com/v1/current.json?key=${apiKey}&q=${currentUserLocation}&aqi=no&lang=${currentLanguage}`; - let data = await fetch(weatherApi); - parsedData = await data.json(); - if (!parsedData.error) { - // Extract only the necessary fields before saving - const filteredData = { - location: { - name: parsedData.location.name, - }, - current: { - condition: { - text: parsedData.current.condition.text, - icon: parsedData.current.condition.icon, - }, - temp_c: parsedData.current.temp_c, - temp_f: parsedData.current.temp_f, - humidity: parsedData.current.humidity, - feelslike_c: parsedData.current.feelslike_c, - feelslike_f: parsedData.current.feelslike_f, - }, - }; - - // Save filtered weather data to localStorage - localStorage.setItem("weatherParsedData", JSON.stringify(filteredData)); - localStorage.setItem("weatherParsedTime", Date.now()); // Save time of last fetching - localStorage.setItem("weatherParsedLocation", currentUserLocation); // Save user location - localStorage.setItem("weatherParsedLang", currentLanguage); // Save language preference - } - UpdateWeather(); - } else { - setTimeout(UpdateWeather, 25); - } - - function UpdateWeather() { - // Weather data - const conditionText = parsedData.current.condition.text; - const tempCelsius = Math.round(parsedData.current.temp_c); - const tempFahrenheit = Math.round(parsedData.current.temp_f); - const humidity = parsedData.current.humidity; - const feelsLikeCelsius = parsedData.current.feelslike_c; - const feelsLikeFahrenheit = parsedData.current.feelslike_f; - - // Update DOM elements with the weather data - document.getElementById("conditionText").textContent = conditionText; - - // Localize and display temperature and humidity - const localizedHumidity = localizeNumbers(humidity.toString(), currentLanguage); - const localizedTempCelsius = localizeNumbers(tempCelsius.toString(), currentLanguage); - const localizedFeelsLikeCelsius = localizeNumbers(feelsLikeCelsius.toString(), currentLanguage); - const localizedTempFahrenheit = localizeNumbers(tempFahrenheit.toString(), currentLanguage); - const localizedFeelsLikeFahrenheit = localizeNumbers(feelsLikeFahrenheit.toString(), currentLanguage); - - // Set humidity level - const humidityLabel = translations[currentLanguage]?.humidityLevel || translations["en"].humidityLevel; // Fallback to English if translation is missing - document.getElementById("humidityLevel").textContent = `${humidityLabel} ${localizedHumidity}%`; - - // Event Listener for the Fahrenheit toggle - const fahrenheitCheckbox = document.getElementById("fahrenheitCheckbox"); - const updateTemperatureDisplay = () => { - const tempElement = document.getElementById("temp"); - const feelsLikeElement = document.getElementById("feelsLike"); - const feelsLikeLabel = translations[currentLanguage]?.feelsLike || translations["en"].feelsLike; - - if (fahrenheitCheckbox.checked) { - // Update temperature - tempElement.textContent = localizedTempFahrenheit; - const tempUnitF = document.createElement("span"); - tempUnitF.className = "tempUnit"; - tempUnitF.textContent = "°F"; - tempElement.appendChild(tempUnitF); - - // TODO: Change, it's hard-coded for cs language - // Update feels like - const feelsLikeFUnit = currentLanguage === 'cs' ? ' °F' : '°F'; - feelsLikeElement.textContent = `${feelsLikeLabel} ${localizedFeelsLikeFahrenheit}${feelsLikeFUnit}`; - } else { - // Update temperature - tempElement.textContent = localizedTempCelsius; - const tempUnitC = document.createElement("span"); - tempUnitC.className = "tempUnit"; - tempUnitC.textContent = "°C"; - tempElement.appendChild(tempUnitC); - - // TODO: Change, it's hard-coded for cs language - // Update feels like - const feelsLikeCUnit = currentLanguage === 'cs' ? ' °C' : '°C'; - feelsLikeElement.textContent = `${feelsLikeLabel} ${localizedFeelsLikeCelsius}${feelsLikeCUnit}`; - } - }; - updateTemperatureDisplay(); - - // Setting weather Icon - const newWIcon = parsedData.current.condition.icon; - const weatherIcon = newWIcon.replace("//cdn", "https://cdn"); - document.getElementById("wIcon").src = weatherIcon; - - // TODO: Change, it's hard-coded for only few languages - // Define minimum width for the slider based on the language - const humidityMinWidth = { - idn: "47%", - hu: "48%", - en: "42%", // Default for English and others - }; - const slider = document.getElementById("slider"); - slider.style.minWidth = humidityMinWidth[currentLanguage] || humidityMinWidth["en"]; - - // Set slider width based on humidity - if (humidity > 40) { - slider.style.width = `calc(${humidity}% - 60px)`; - } - - // Update location - var city = parsedData.location.name; - // var city = "Thiruvananthapuram"; - var maxLength = 10; - var limitedText = city.length > maxLength ? city.substring(0, maxLength) + "..." : city; - document.getElementById("location").textContent = limitedText; - - } - } catch (error) { - console.error("Error fetching weather data:", error); - } - } - - // Function to fetch GPS-based location - async function fetchGPSLocation() { - try { - const getLocationFromGPS = () => { - return new Promise((resolve, reject) => { - navigator.geolocation.getCurrentPosition( - (position) => { - resolve({ - latitude: position.coords.latitude, - longitude: position.coords.longitude, - }); - }, - (error) => reject(error), - { timeout: 4000 } - ); - }); - }; - - const { latitude, longitude } = await getLocationFromGPS(); - return `${latitude},${longitude}`; - } catch (error) { - console.error("GPS Location retrieval failed: ", error); - } - } - - // Fetch location dynamically based on user preference - await (async function initializeLocation() { - try { - if (useGPS) { - try { - // Use GPS for dynamic location - currentUserLocation = await fetchGPSLocation(); - } catch { - // Silent failover - } - } - - if (!currentUserLocation) { - // Fallback to IP-based location if no manual input - const geoLocation = "https://ipinfo.io/json/"; - const locationData = await fetch(geoLocation); - const parsedLocation = await locationData.json(); - currentUserLocation = parsedLocation.loc; - } - - // Fetch weather data - fetchWeather(currentUserLocation); - } catch (error) { - console.error("Failed to determine location:", error); - currentUserLocation = "auto:ip"; - fetchWeather(currentUserLocation); - } - })(); - - // Handle "Use GPS" button click - useGPSButton.addEventListener("click", () => { - // Set the flag to use GPS dynamically and remove manual location - localStorage.setItem("useGPS", true); - localStorage.removeItem("weatherLocation"); - location.reload(); - }); - - // Handle manual location input - saveLocButton.addEventListener("click", () => { - const userLocation = userLocInput.value.trim(); - localStorage.setItem("weatherLocation", userLocation); - localStorage.setItem("useGPS", false); - userLocInput.value = ""; - fetchWeather(userLocation); - location.reload(); - }); }); -// ---------------------------end of weather stuff-------------------- - - -document.addEventListener("DOMContentLoaded", () => { - const userTextDiv = document.getElementById("userText"); - const userTextCheckbox = document.getElementById("userTextCheckbox"); - - // Load and apply the checkbox state - const isUserTextVisible = localStorage.getItem("userTextVisible") !== "false"; - userTextCheckbox.checked = isUserTextVisible; - userTextDiv.style.display = isUserTextVisible ? "block" : "none"; - - // Toggle userText display based on checkbox state - userTextCheckbox.addEventListener("change", () => { - const isVisible = userTextCheckbox.checked; - userTextDiv.style.display = isVisible ? "block" : "none"; - localStorage.setItem("userTextVisible", isVisible); - }); - - // Set the default language to English if no language is saved - const savedLang = localStorage.getItem("selectedLanguage") || "en"; - applyLanguage(savedLang); - - // Load the stored text if it exists - const storedValue = localStorage.getItem("userText"); - if (storedValue) { - userTextDiv.textContent = storedValue; - } else { - // Fallback to the placeholder based on the selected language - const placeholder = userTextDiv.dataset.placeholder || translations["en"].userText; // Fallback to English - userTextDiv.textContent = placeholder; - } - - // Handle input event - userTextDiv.addEventListener("input", function () { - localStorage.setItem("userText", userTextDiv.textContent); - }); - - // Remove placeholder text when the user starts editing - userTextDiv.addEventListener("focus", function () { - if (userTextDiv.textContent === userTextDiv.dataset.placeholder) { - userTextDiv.textContent = ""; // Clear the placeholder when focused - } - }); - // Restore placeholder if the user leaves the div empty after editing - userTextDiv.addEventListener("blur", function () { - if (userTextDiv.textContent === "") { - userTextDiv.textContent = userTextDiv.dataset.placeholder; // Show the placeholder again if empty - } - }); -}); +// --------------------------- Search Bar ------------------------------------ // Showing border or outline when you click on the searchbar const searchbar = document.getElementById("searchbar"); @@ -1023,14 +693,11 @@ const applySelectedTheme = (colorValue) => { // Function to update the extension icon based on browser const updateExtensionIcon = (colorValue) => { - if (typeof browser !== "undefined" && browser.browserAction) { - // Firefox + if (isFirefox) { browser.browserAction.setIcon({ path: iconPaths[colorValue] }); - } else if (typeof chrome !== "undefined" && chrome.action) { - // Chromium-based: Chrome, Edge, Brave + } else if (isChromiumBased) { chrome.action.setIcon({ path: iconPaths[colorValue] }); - } else if (typeof safari !== "undefined") { - // Safari + } else if (isSafari) { safari.extension.setToolbarIcon({ path: iconPaths[colorValue] }); } }; @@ -1265,23 +932,13 @@ document.getElementById("searchQ").addEventListener("keydown", function (e) { } }); +// Check for different browsers and return the corresponding client parameter function getClientParam() { - const userAgent = navigator.userAgent.toLowerCase(); - - // Check for different browsers and return the corresponding client parameter - if (userAgent.includes("firefox")) { - return "firefox"; - } else if (userAgent.includes("chrome") || userAgent.includes("crios")) { - return "chrome"; - } else if (userAgent.includes("safari")) { - return "safari"; - } else if (userAgent.includes("edge") || userAgent.includes("edg")) { - return "firefox"; - } else if (userAgent.includes("opera") || userAgent.includes("opr")) { - return "opera"; - } else { - return "firefox"; // Default to Firefox client if the browser is not recognized - } + if (isFirefox) return "firefox"; + if (isChromiumBased && !isOpera) return "chrome"; + if (isOpera) return "opera"; + if (isSafari) return "safari"; + return "firefox"; // Default to Firefox if the browser is not recognized } async function getAutocompleteSuggestions(query) { @@ -1500,15 +1157,10 @@ document.addEventListener("DOMContentLoaded", function () { const shortcuts = document.getElementById("shortcuts-section"); const shortcutsCheckbox = document.getElementById("shortcutsCheckbox"); - const proxybypassField = document.getElementById("proxybypassField"); - const proxyinputField = document.getElementById("proxyField"); - const useproxyCheckbox = document.getElementById("useproxyCheckbox"); const searchsuggestionscheckbox = document.getElementById("searchsuggestionscheckbox"); const shortcutEditField = document.getElementById("shortcutEditField"); const adaptiveIconField = document.getElementById("adaptiveIconField"); const adaptiveIconToggle = document.getElementById("adaptiveIconToggle"); - const hideWeatherCheckbox = document.getElementById("hideWeatherCheckbox"); - const fahrenheitCheckbox = document.getElementById("fahrenheitCheckbox"); const shortcutEditButton = document.getElementById("shortcutEditButton"); const backButton = document.getElementById("backButton"); const shortcutSettingsContainer = document.getElementById("shortcutList"); // shortcuts in settings @@ -1518,6 +1170,10 @@ document.addEventListener("DOMContentLoaded", function () { const iconStyle = document.getElementById("iconStyle"); const enableDarkModeCheckbox = document.getElementById("enableDarkModeCheckbox"); + const proxybypassField = document.getElementById("proxybypassField"); + const proxyinputField = document.getElementById("proxyField"); + const useproxyCheckbox = document.getElementById("useproxyCheckbox"); + // const flexMonitor = document.getElementById("flexMonitor"); // monitors whether shortcuts have flex-wrap flexed // const defaultHeight = document.getElementById("defaultMonitor").clientHeight; // used to compare to previous element @@ -2058,14 +1714,6 @@ document.addEventListener("DOMContentLoaded", function () { saveCheckboxState("enableDarkModeCheckboxState", enableDarkModeCheckbox); }); - hideWeatherCheckbox.addEventListener("change", function () { - saveCheckboxState("hideWeatherCheckboxState", hideWeatherCheckbox); - }); - - fahrenheitCheckbox.addEventListener("change", function () { - saveCheckboxState("fahrenheitCheckboxState", fahrenheitCheckbox); - }); - newShortcutButton.addEventListener("click", () => newShortcut()); resetShortcutsButton.addEventListener("click", () => resetShortcuts()); @@ -2129,9 +1777,7 @@ document.addEventListener("DOMContentLoaded", function () { loadCheckboxState("useproxyCheckboxState", useproxyCheckbox); loadActiveStatus("proxyinputField", proxyinputField); loadActiveStatus("proxybypassField", proxybypassField); - loadCheckboxState("hideWeatherCheckboxState", hideWeatherCheckbox); loadDisplayStatus("shortcutsDisplayStatus", shortcuts); - loadCheckboxState("fahrenheitCheckboxState", fahrenheitCheckbox); loadCheckboxState("enableDarkModeCheckboxState", enableDarkModeCheckbox); loadShortcuts(); }); diff --git a/scripts/voice-search.js b/scripts/voice-search.js index 9c41c47d..85bf0f14 100644 --- a/scripts/voice-search.js +++ b/scripts/voice-search.js @@ -133,4 +133,4 @@ function initializeSpeechRecognition() { if (!micIconCheckbox.checked) { initializeSpeechRecognition(); } -// -----------End of Voice Search------------ +// -----------End of Voice Search------------ \ No newline at end of file diff --git a/scripts/wallpaper.js b/scripts/wallpaper.js index d0834cc9..bad36d82 100644 --- a/scripts/wallpaper.js +++ b/scripts/wallpaper.js @@ -6,6 +6,9 @@ * If not, see . */ +// Get the current language from localStorage +const currentLanguage = localStorage.getItem("selectedLanguage") || "en"; + // -------------------------- Wallpaper ----------------------------- const dbName = "ImageDB"; const storeName = "backgroundImages"; @@ -100,7 +103,6 @@ document.getElementById("imageUpload").addEventListener("change", function (even // Fetch and apply random image as background const RANDOM_IMAGE_URL = "https://picsum.photos/1920/1080"; -const currentLanguage = getLanguageStatus("selectedLanguage") || "en"; async function applyRandomImage(showConfirmation = true) { if (showConfirmation && !confirm(translations[currentLanguage]?.confirmWallpaper || translations["en"].confirmWallpaper)) { @@ -222,4 +224,4 @@ document.getElementById("randomImageTrigger").addEventListener("click", applyRan // Start image check on page load checkAndUpdateImage(); -// ------------------------ End of BG Image -------------------------- +// ------------------------ End of BG Image -------------------------- \ No newline at end of file diff --git a/scripts/weather.js b/scripts/weather.js new file mode 100644 index 00000000..2daf2f15 --- /dev/null +++ b/scripts/weather.js @@ -0,0 +1,293 @@ +/* + * Material You NewTab + * Copyright (c) 2023-2025 XengShi + * Licensed under the GNU General Public License v3.0 (GPL-3.0) + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + */ + +window.addEventListener("DOMContentLoaded", async () => { + // Cache DOM elements + const userAPIInput = document.getElementById("userAPI"); + const userLocInput = document.getElementById("userLoc"); + const saveAPIButton = document.getElementById("saveAPI"); + const saveLocButton = document.getElementById("saveLoc"); + const useGPSButton = document.getElementById("useGPS"); + + // Load saved data from localStorage + const savedApiKey = localStorage.getItem("weatherApiKey"); + const savedLocation = localStorage.getItem("weatherLocation"); + + // Pre-fill input fields with saved data + if (savedLocation) userLocInput.value = savedLocation; + if (savedApiKey) userAPIInput.value = savedApiKey; + + // Function to simulate button click on Enter key press + function handleEnterPress(event, buttonId) { + if (event.key === "Enter") { + document.getElementById(buttonId).click(); + } + } + + // Add event listeners for handling Enter key presses + userAPIInput.addEventListener("keydown", (event) => handleEnterPress(event, "saveAPI")); + userLocInput.addEventListener("keydown", (event) => handleEnterPress(event, "saveLoc")); + + // Save API key to localStorage + saveAPIButton.addEventListener("click", () => { + const apiKey = userAPIInput.value.trim(); + localStorage.setItem("weatherApiKey", apiKey); + userAPIInput.value = ""; + location.reload(); + }); + + // Default Weather API key + const weatherApiKeys = [ + "d36ce712613d4f21a6083436240910", + "db0392b338114f208ee135134240312", + "de5f7396db034fa2bf3140033240312", + "c64591e716064800992140217240312", + "9b3204c5201b4b4d8a2140330240312", + "eb8a315c15214422b60140503240312", + "cd148ebb1b784212b74140622240312", + "7ae67e219af54df2840140801240312", + "0a6bc8a404224c8d89953341241912", + "f59e58d7735d4739ae953115241912" + ]; + const defaultApiKey = weatherApiKeys[Math.floor(Math.random() * weatherApiKeys.length)]; + + // Determine which API key to use + const apiKey = savedApiKey || defaultApiKey; + + // Determine the location to use + let currentUserLocation = savedLocation; + + // Flag indicating whether to use GPS + const useGPS = JSON.parse(localStorage.getItem("useGPS")); + + // Fetch weather data based on a location + async function fetchWeather() { + try { + let parsedData = JSON.parse(localStorage.getItem("weatherParsedData")); + const weatherParsedTime = parseInt(localStorage.getItem("weatherParsedTime")); + const weatherParsedLocation = localStorage.getItem("weatherParsedLocation"); + const weatherParsedLang = localStorage.getItem("weatherParsedLang"); + + const retentionTime = savedApiKey ? 120000 : 960000; // 2 min for user-entered API key, 16 min otherwise + + if (!parsedData || ((Date.now() - weatherParsedTime) > retentionTime) || (weatherParsedLocation !== currentUserLocation) || (weatherParsedLang !== currentLanguage)) { + // Fetch weather data using Weather API + let weatherApi = `https://api.weatherapi.com/v1/current.json?key=${apiKey}&q=${currentUserLocation}&aqi=no&lang=${currentLanguage}`; + let data = await fetch(weatherApi); + parsedData = await data.json(); + if (!parsedData.error) { + // Extract only the necessary fields before saving + const filteredData = { + location: { + name: parsedData.location.name, + }, + current: { + condition: { + text: parsedData.current.condition.text, + icon: parsedData.current.condition.icon, + }, + temp_c: parsedData.current.temp_c, + temp_f: parsedData.current.temp_f, + humidity: parsedData.current.humidity, + feelslike_c: parsedData.current.feelslike_c, + feelslike_f: parsedData.current.feelslike_f, + }, + }; + + // Save filtered weather data to localStorage + localStorage.setItem("weatherParsedData", JSON.stringify(filteredData)); + localStorage.setItem("weatherParsedTime", Date.now()); // Save time of last fetching + localStorage.setItem("weatherParsedLocation", currentUserLocation); // Save user location + localStorage.setItem("weatherParsedLang", currentLanguage); // Save language preference + } + UpdateWeather(); + } else { + setTimeout(UpdateWeather, 50); + } + + function UpdateWeather() { + // Weather data + const conditionText = parsedData.current.condition.text; + const tempCelsius = Math.round(parsedData.current.temp_c); + const tempFahrenheit = Math.round(parsedData.current.temp_f); + const humidity = parsedData.current.humidity; + const feelsLikeCelsius = parsedData.current.feelslike_c; + const feelsLikeFahrenheit = parsedData.current.feelslike_f; + + // Update DOM elements with the weather data + document.getElementById("conditionText").textContent = conditionText; + + // Localize and display temperature and humidity + const localizedHumidity = localizeNumbers(humidity.toString(), currentLanguage); + const localizedTempCelsius = localizeNumbers(tempCelsius.toString(), currentLanguage); + const localizedFeelsLikeCelsius = localizeNumbers(feelsLikeCelsius.toString(), currentLanguage); + const localizedTempFahrenheit = localizeNumbers(tempFahrenheit.toString(), currentLanguage); + const localizedFeelsLikeFahrenheit = localizeNumbers(feelsLikeFahrenheit.toString(), currentLanguage); + + // Set humidity level + const humidityLabel = translations[currentLanguage]?.humidityLevel || translations["en"].humidityLevel; // Fallback to English if translation is missing + document.getElementById("humidityLevel").textContent = `${humidityLabel} ${localizedHumidity}%`; + + // Event Listener for the Fahrenheit toggle + const fahrenheitCheckbox = document.getElementById("fahrenheitCheckbox"); + const updateTemperatureDisplay = () => { + const tempElement = document.getElementById("temp"); + const feelsLikeElement = document.getElementById("feelsLike"); + const feelsLikeLabel = translations[currentLanguage]?.feelsLike || translations["en"].feelsLike; + + // List of languages where a space before °F or °C is required + const langWithSpaceBeforeDegree = ['cs']; + + if (fahrenheitCheckbox.checked) { + // Update temperature + tempElement.textContent = localizedTempFahrenheit; + const tempUnitF = document.createElement("span"); + tempUnitF.className = "tempUnit"; + tempUnitF.textContent = "°F"; + tempElement.appendChild(tempUnitF); + + // Update feels like + const feelsLikeFUnit = langWithSpaceBeforeDegree.includes(currentLanguage) ? ' °F' : '°F'; + feelsLikeElement.textContent = `${feelsLikeLabel} ${localizedFeelsLikeFahrenheit}${feelsLikeFUnit}`; + } else { + // Update temperature + tempElement.textContent = localizedTempCelsius; + const tempUnitC = document.createElement("span"); + tempUnitC.className = "tempUnit"; + tempUnitC.textContent = "°C"; + tempElement.appendChild(tempUnitC); + + // Update feels like + const feelsLikeCUnit = langWithSpaceBeforeDegree.includes(currentLanguage) ? ' °C' : '°C'; + feelsLikeElement.textContent = `${feelsLikeLabel} ${localizedFeelsLikeCelsius}${feelsLikeCUnit}`; + } + }; + updateTemperatureDisplay(); + + // Setting weather Icon + const newWIcon = parsedData.current.condition.icon; + const weatherIcon = newWIcon.replace("//cdn", "https://cdn"); + document.getElementById("wIcon").src = weatherIcon; + + // Define minimum width for the slider based on the language + const humidityMinWidth = { + idn: "47%", + hu: "48%", + en: "42%", // Default for English and others + }; + const slider = document.getElementById("slider"); + slider.style.minWidth = humidityMinWidth[currentLanguage] || humidityMinWidth["en"]; + + // Set slider width based on humidity + if (humidity > 40) { + slider.style.width = `calc(${humidity}% - 60px)`; + } + + // Update location + var city = parsedData.location.name; + // var city = "Thiruvananthapuram"; + var maxLength = 10; + var limitedText = city.length > maxLength ? city.substring(0, maxLength) + "..." : city; + document.getElementById("location").textContent = limitedText; + + } + } catch (error) { + console.error("Error fetching weather data:", error); + } + } + + // Function to fetch GPS-based location + async function fetchGPSLocation() { + try { + const getLocationFromGPS = () => { + return new Promise((resolve, reject) => { + navigator.geolocation.getCurrentPosition( + (position) => { + resolve({ + latitude: position.coords.latitude, + longitude: position.coords.longitude, + }); + }, + (error) => reject(error), + { timeout: 4000 } + ); + }); + }; + + const { latitude, longitude } = await getLocationFromGPS(); + return `${latitude},${longitude}`; + } catch (error) { + console.error("GPS Location retrieval failed: ", error); + } + } + + // Fetch location dynamically based on user preference + await (async function initializeLocation() { + try { + if (useGPS) { + try { + // Use GPS for dynamic location + currentUserLocation = await fetchGPSLocation(); + } catch { + console.log("Failed to use GPS for location:", error); + } + } + + if (!currentUserLocation) { + // Fallback to IP-based location if no manual input + const geoLocation = "https://ipinfo.io/json/"; + const locationData = await fetch(geoLocation); + const parsedLocation = await locationData.json(); + currentUserLocation = parsedLocation.loc; + } + + // Fetch weather data + fetchWeather(currentUserLocation); + } catch (error) { + console.error("Failed to determine location:", error); + currentUserLocation = "auto:ip"; + fetchWeather(currentUserLocation); + } + })(); + + // Handle "Use GPS" button click + useGPSButton.addEventListener("click", () => { + // Set the flag to use GPS dynamically and remove manual location + localStorage.setItem("useGPS", true); + localStorage.removeItem("weatherLocation"); + location.reload(); + }); + + // Handle manual location input + saveLocButton.addEventListener("click", () => { + const userLocation = userLocInput.value.trim(); + localStorage.setItem("weatherLocation", userLocation); + localStorage.setItem("useGPS", false); + userLocInput.value = ""; + fetchWeather(userLocation); + location.reload(); + }); +}); + + +// Save and load toggle state +document.addEventListener("DOMContentLoaded", function () { + const hideWeatherCheckbox = document.getElementById("hideWeatherCheckbox"); + const fahrenheitCheckbox = document.getElementById("fahrenheitCheckbox"); + + hideWeatherCheckbox.addEventListener("change", function () { + saveCheckboxState("hideWeatherCheckboxState", hideWeatherCheckbox); + }); + + fahrenheitCheckbox.addEventListener("change", function () { + saveCheckboxState("fahrenheitCheckboxState", fahrenheitCheckbox); + }); + + loadCheckboxState("hideWeatherCheckboxState", hideWeatherCheckbox); + loadCheckboxState("fahrenheitCheckboxState", fahrenheitCheckbox); +}); \ No newline at end of file