deafone

Google Maps Addon (Simplified ES6+)

Jun 18th, 2025
38
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
JavaScript 5.84 KB | Source Code | 0 0
  1. // ==UserScript==
  2. // @name         Google Maps Addon (Simplified ES6+)
  3. // @namespace    http://tampermonkey.net/
  4. // @version      2025-06-19
  5. // @description  Restore Maps button on Google Search + update map thumbnail link in preview. Handles AJAX/SPAs and Tampermonkey GUI settings. Static English labels, optimized logic, uses stable attribute selector for map preview container.
  6. // @author       You
  7. // @match        https://www.google.com/search*
  8. // @grant        GM_registerMenuCommand
  9. // @grant        GM_getValue
  10. // @grant        GM_setValue
  11. // ==/UserScript==
  12.  
  13. (() => {
  14.     'use strict';
  15.  
  16.     // =======================
  17.     // Configuration
  18.     // =======================
  19.     const defaultSettings = {
  20.         enableMapsButton: true,
  21.         enableThumbnailUpdate: true
  22.     };
  23.  
  24.     // Simple wrapper around GM_getValue/GM_setValue with defaults
  25.     const settings = {
  26.         get: key => GM_getValue(key, defaultSettings[key]),
  27.         set: (key, value) => GM_setValue(key, value)
  28.     };
  29.  
  30.     // Register Tampermonkey menu items to toggle features
  31.     const registerSettingsMenu = () => {
  32.         GM_registerMenuCommand(
  33.             `Maps Button: ${settings.get('enableMapsButton') ? 'ON' : 'OFF'}`,
  34.             () => toggleSetting('enableMapsButton')
  35.         );
  36.         GM_registerMenuCommand(
  37.             `Map Thumbnail Update: ${settings.get('enableThumbnailUpdate') ? 'ON' : 'OFF'}`,
  38.             () => toggleSetting('enableThumbnailUpdate')
  39.         );
  40.     };
  41.  
  42.     // Toggle a boolean setting and reload to apply
  43.     const toggleSetting = key => {
  44.         const newValue = !settings.get(key);
  45.         settings.set(key, newValue);
  46.         alert(`Setting changed: ${key} → ${newValue ? 'ON' : 'OFF'}. Reloading...`);
  47.         location.reload();
  48.     };
  49.  
  50.     // =======================
  51.     // Utility functions
  52.     // =======================
  53.     const getQuery = () => new URLSearchParams(location.search).get('q') || '';
  54.  
  55.     // Build the Maps URL for the current query
  56.     const buildMapsHref = () => `https://maps.google.com/maps?q=${encodeURIComponent(getQuery())}`;
  57.  
  58.     // =======================
  59.     // Create and insert Maps button in horizontal tabs
  60.     // =======================
  61.     const createMapsButton = href => {
  62.         // Reuse Google’s classes for visual consistency
  63.         const a = document.createElement('a');
  64.         a.className = 'nPDzT T3FoJb gpt-maps-btn';
  65.         a.href = href;
  66.         a.target = '_blank';
  67.         a.rel = 'noopener noreferrer';
  68.  
  69.         const div = document.createElement('div');
  70.         div.className = 'GKS7s';
  71.         div.setAttribute('jsname', 'bVqjv');
  72.  
  73.         const span = document.createElement('span');
  74.         span.className = 'FMKtTb UqcIvb';
  75.         span.setAttribute('jsname', 'pIvPIe');
  76.         span.style.fontWeight = 'bold';
  77.         span.textContent = 'Maps'; // static English label
  78.  
  79.         div.appendChild(span);
  80.         a.appendChild(div);
  81.         return a;
  82.     };
  83.  
  84.     const insertMapsButton = () => {
  85.         if (!settings.get('enableMapsButton')) return;
  86.         const tabs = document.querySelector('.IUOThf');
  87.         if (!tabs || tabs.querySelector('.gpt-maps-btn')) return;
  88.  
  89.         const href = buildMapsHref();
  90.         const button = createMapsButton(href);
  91.         tabs.appendChild(button);
  92.     };
  93.  
  94.     // =======================
  95.     // Observe and update map thumbnail in the right-side preview
  96.     // =======================
  97.     const observeMapThumbnail = () => {
  98.         if (!settings.get('enableThumbnailUpdate')) return;
  99.  
  100.         const updateThumbs = () => {
  101.             const href = buildMapsHref();
  102.             // Find all containers with stable attribute jscontroller="lvAdvf"
  103.             document.querySelectorAll('[jscontroller="lvAdvf"]').forEach(container => {
  104.                 const thumbLink = container.querySelector('a');
  105.                 if (!thumbLink) return;
  106.                 // Skip if already correct
  107.                 if (thumbLink.href === href) return;
  108.  
  109.                 // Update link
  110.                 Object.assign(thumbLink, {
  111.                     href,
  112.                     target: '_blank',
  113.                     rel: 'noopener noreferrer'
  114.                 });
  115.  
  116.                 // Add a label if not already present
  117.                 // Use a distinctive class to avoid duplicating
  118.                 if (!thumbLink.querySelector('.z3dsh')) {
  119.                     const label = document.createElement('span');
  120.                     label.className = 'z3dsh';
  121.                     label.textContent = 'View on Maps'; // static English label
  122.                     thumbLink.appendChild(label);
  123.                 }
  124.             });
  125.         };
  126.  
  127.         // Observe DOM changes so that if Google re-renders preview, we update again
  128.         const observer = new MutationObserver(() => {
  129.             updateThumbs();
  130.         });
  131.         observer.observe(document.body, { childList: true, subtree: true });
  132.  
  133.         // Initial run
  134.         updateThumbs();
  135.     };
  136.  
  137.     // =======================
  138.     // Handle dynamic SPA changes for the horizontal tabs
  139.     // =======================
  140.     const observePageChanges = () => {
  141.         const observer = new MutationObserver(() => {
  142.             insertMapsButton();
  143.         });
  144.         observer.observe(document.body, { childList: true, subtree: true });
  145.     };
  146.  
  147.     // Wait until Google’s horizontal tabs container appears, then insert button
  148.     const waitForGoogleTabs = () => {
  149.         const interval = setInterval(() => {
  150.             if (document.querySelector('.IUOThf')) {
  151.                 clearInterval(interval);
  152.                 insertMapsButton();
  153.             }
  154.         }, 250);
  155.     };
  156.  
  157.     // =======================
  158.     // Initialization
  159.     // =======================
  160.     registerSettingsMenu();
  161.     waitForGoogleTabs();
  162.     observePageChanges();
  163.     observeMapThumbnail();
  164.  
  165. })();
Add Comment
Please, Sign In to add comment