Fix Gmail Email Search

Improved version of the old "Emails" quick search functionality in Gmail, one click to view all emails you've sent or received from any address

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Fix Gmail Email Search
// @namespace    https://github.com/gserafini/fix-gmail-email-search-userscript/
// @version      1.5.1
// @description  Improved version of the old "Emails" quick search functionality in Gmail, one click to view all emails you've sent or received from any address
// @author       Gabriel Serafini
// @license      MIT
// @donate       If you like this, PayPal a little love to [email protected] (or https://paypal.me/SerafiniStudios )
// @screenshot   https://raw.githubusercontent.com/gserafini/fix-gmail-email-search-userscript/master/fix-gmail-email-search-screenshot.png
// @icon         https://raw.githubusercontent.com/gserafini/fix-gmail-email-search-userscript/master/SearchEmails_icon.png
// @match        *://mail.google.com/*
// @match        *://contacts.google.com/*
// @match        *://gmail.com/*
// @grant        none
// ==/UserScript==

// Changelog:
// v1.5.1 - Bug fix: Fixed @match directive for contacts.google.com to support
//          Google Workspace accounts with /u/1/ paths (hovercards now work on all accounts)
// v1.5.0 - Major rewrite: Removed jQuery dependency, now uses pure vanilla JavaScript
//          No longer requires separate TrustedHTML bypass script
//          Uses native DOM methods (createElement, createElementNS) instead of innerHTML
//          Smaller, faster, and bypasses TrustedTypes restrictions without workarounds

(function() {
    'use strict';

    // Add styles using textContent (no TrustedTypes issues)
    var style = document.createElement('style');
    style.textContent = '.email_search_icon { outline: none; position: relative; z-index: 0; padding: 0 4px; margin: 0; top: 2px; cursor: pointer; } ' +
                        '.email_search_icon svg { fill: #600; } ' +
                        '.email_search_icon svg:hover { fill: #f00; }';
    document.head.appendChild(style);

    // Create search icon element using DOM methods (no innerHTML)
    function createEmailSearchIcon(emailAddress) {
        var span = document.createElement('span');
        span.className = 'email_search_icon';
        span.title = 'Click to search for all emails with ' + emailAddress;
        span.setAttribute('email', emailAddress);

        // Create SVG using createElementNS
        var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
        svg.setAttribute('focusable', 'false');
        svg.setAttribute('height', '1em');
        svg.setAttribute('viewBox', '0 0 24 24');
        svg.setAttribute('width', '1em');

        var path1 = document.createElementNS('http://www.w3.org/2000/svg', 'path');
        path1.setAttribute('d', 'M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z');

        var path2 = document.createElementNS('http://www.w3.org/2000/svg', 'path');
        path2.setAttribute('d', 'M0 0h24v24H0z');
        path2.setAttribute('fill', 'none');

        svg.appendChild(path1);
        svg.appendChild(path2);
        span.appendChild(svg);

        return span;
    }

    // Check if element already has icon
    function hasIcon(element) {
        var prev = element.previousElementSibling;
        return prev && prev.classList.contains('email_search_icon');
    }

    function insertEmailSearchIcons() {
        // Find Gmail email elements (.gD class)
        var gdElements = document.querySelectorAll('.gD');
        for (var i = 0; i < gdElements.length; i++) {
            var el = gdElements[i];
            if (!hasIcon(el)) {
                var email = el.getAttribute('email');
                if (email) {
                    var gdIcon = createEmailSearchIcon(email);
                    el.parentNode.insertBefore(gdIcon, el);
                }
            }
        }

        // Find mailto links (excluding contenteditable divs)
        var mailtoLinks = document.querySelectorAll('a[href^="mailto:"]');
        for (var j = 0; j < mailtoLinks.length; j++) {
            var link = mailtoLinks[j];
            // Skip if inside contenteditable div
            var inEditable = link.closest('div[contenteditable="true"]');
            if (!inEditable && !hasIcon(link)) {
                var href = link.getAttribute('href');
                var emailAddr = href.replace('mailto:', '');
                var mailtoIcon = createEmailSearchIcon(emailAddr);
                link.parentNode.insertBefore(mailtoIcon, link);
            }
        }
    }

    // Poll periodically for newly created elements
    setInterval(insertEmailSearchIcons, 300);

    // Handle click events using event delegation
    document.addEventListener('click', function(event) {
        var target = event.target;

        // Find closest .email_search_icon (handles clicks on SVG children)
        var icon = target.closest('.email_search_icon');
        if (!icon) return;

        event.stopPropagation();

        var email = icon.getAttribute('email');

        if (window.self === window.top) {
            // Main window - perform search
            var searchInput = document.querySelector('input[name="q"]');
            var searchButton = document.querySelector('button[aria-label="Search mail"]');

            if (searchInput && searchButton) {
                searchInput.value = email;
                searchButton.click();
            }
        } else {
            // Iframe (hovercard) - send message to parent
            window.parent.postMessage('searchForEmail=' + email, '*');
        }
    });

    // Listen for messages from iframe (hovercard)
    if (window.self === window.top) {
        window.addEventListener('message', function(event) {
            if (event.origin === 'https://contacts.google.com' &&
                typeof event.data === 'string' &&
                event.data.indexOf('searchForEmail=') !== -1) {

                var email = event.data.replace('searchForEmail=', '');
                var searchInput = document.querySelector('input[name="q"]');
                var searchButton = document.querySelector('button[aria-label="Search mail"]');

                if (searchInput && searchButton) {
                    searchInput.value = email;
                    searchButton.click();
                }
            }
        });
    }

})();