Add an advanced search form to the top of the page
// ==UserScript== // @name Advanced Search Assistant for Google // @name:zh-CN Google 高级搜索助手 // @namespace http://tampermonkey.net/ // @version 0.1.8 // @description Add an advanced search form to the top of the page // @description:zh-CN 在谷歌搜索页面顶部添加一个高级搜索表单 // @author shiquda // @namespace https://github.com/shiquda/shiquda_UserScript // @supportURL https://github.com/shiquda/shiquda_UserScript/issues // @match *://www.google.com/search* // @include *://*google*/search* // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @license MIT // ==/UserScript== (function () { "use strict"; let isMobile = false; if ( navigator.userAgent.match(/Android/i) || navigator.userAgent.match(/webOS/i) || navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i) || navigator.userAgent.match(/iPod/i) || navigator.userAgent.match(/BlackBerry/i) || navigator.userAgent.match(/Windows Phone/i) ) { // On mobile device isMobile = true; } let isDarkMode = false; try { if ( window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches ) { // Dark mode is enabled isDarkMode = true; console.log("Dark mode is enabled."); } } catch (error) { console.log("Failed to determine the color mode.", error); } const userLanguage = ""; // You can set your language config here manually. 'zh-CN' & 'en' are supported now. const supportedLanguages = ["zh-CN", "en"]; const translation = { as_q: { "zh-CN": "搜索字词:", en: "Search word:", }, as_epq: { "zh-CN": "与以下字词完全匹配:", en: "Match the following words exactly:", }, as_oq: { "zh-CN": "包含以下任意字词:", en: "Contains any of the following words:", }, as_eq: { "zh-CN": "排除以下字词:", en: "Exclude the following words:", }, as_nlo: { "zh-CN": "包含的数字范围:从", en: "Number range: from", }, as_nhi: { "zh-CN": "到:", en: "to:", }, lr: { "zh-CN": "语言:", en: "Language:", }, cr: { "zh-CN": "地区:", en: "Region:", }, as_qdr: { "zh-CN": "最后更新时间:", en: "Last update time:", }, as_sitesearch: { "zh-CN": "网站或域名:", en: "Website or domain:", }, as_occt: { "zh-CN": "字词出现位置:", en: "Word position:", }, as_filetype: { "zh-CN": "文件类型:", en: "File type:", }, tbs: { "zh-CN": "使用权限:", en: "Usage rights:", }, advancedSearch: { "zh-CN": "高级搜索", en: "Advanced Search", }, search: { "zh-CN": "搜索", en: "Search", }, clear: { "zh-CN": "清空", en: "Clear", }, as_qdr_select: { "": { "zh-CN": "请选择", en: "Please select", }, d: { "zh-CN": "一天内", en: "Past 24 hours", }, w: { "zh-CN": "一周内", en: "Past week", }, m: { "zh-CN": "一月内", en: "Past month", }, y: { "zh-CN": "一年内", en: "Past year", }, }, as_occt_select: { "": { "zh-CN": "请选择", en: "Please select", }, title: { "zh-CN": "网页标题中", en: "In the title of the web page", }, body: { "zh-CN": "网页正文中", en: "In the body of the web page", }, url: { "zh-CN": "网页网址中", en: "In the URL of the web page", }, links: { "zh-CN": "指向网页的链接中", en: "In the links to the web page", }, }, }; const style = ` #advancedSearchToggleButton { margin-right: 10px; border: none; border-radius: 5px; background-color: #007bff; color: #fff; font-size: 14px; font-weight: bold; margin: 10px; } #advancedSearchFormContainer { position: fixed; ${isMobile ? "top: 150px;" : "top: 130px;"} ${isMobile ? "left: 15px;" : "left: 30px;"} display: none; padding: 10px; border: 1px solid #ccc; border-radius: 5px; font-size: 14px; font-weight: bold; ${isDarkMode ? "background-color: rgba(0, 0, 0, 1);" : "background-color: rgba(255, 255, 255, 1);" } ${isMobile ? "column-count: 2;" : ""} /* 在移动设备上分为两列 */ z-index: 1000; // Make sure the button is on top of the search bar } #advancedSearchFormContainer label { display: block; margin-top: 5px; } #advancedSearchFormContainer input[type="text"] { margin-top: 5px; padding: 5px; border: 1px solid #ccc; border-radius: 5px; } #advancedSearchFormContainer select { margin-top: 5px; padding: 5px; border-radius: 5px; } #advancedSearchFormContainer button { border: none; border-radius: 5px; background-color: #007bff; color: #fff; font-size: 14px; font-weight: bold; margin: 20px; } `; GM_addStyle(style); let language = "en"; if (userLanguage.length > 0) { // userLanguage is set manually if (supportedLanguages.includes(userLanguage)) { language = userLanguage; } else { console.log(`Unsupported language: ${userLanguage}`); } } else { // Check if any of the user's preferred languages are supported language = navigator.languages .map((lang) => lang.split("-")[0]) // Consider only the language part, not the region .map((lang) => supportedLanguages.find((supportedLang) => supportedLang.split("-")[0] === lang)) // Match with the supported languages .filter(Boolean) // Remove undefined values .shift() // Take the first matched language || "en"; // Default to 'en' if no match found console.log(`Here is the language: ${language}`); } // Create user interface const toggleButton = document.createElement("button"); toggleButton.className = "nfSF8e"; toggleButton.textContent = translation["advancedSearch"][language]; toggleButton.id = "advancedSearchToggleButton"; if (isMobile) { document.querySelector(".Fh5muf").appendChild(toggleButton); } else { document.querySelector(".logo").appendChild(toggleButton); } // Use the parent element of the search bar const searchContainer = document.querySelector(".RNNXgb"); // Replace with actual selector // Assuming `toggleButton` is your "Advanced Search" button already created searchContainer.appendChild(toggleButton); // Add minimal style for positioning toggleButton.style.marginTop = "5px"; // Add some space above the button toggleButton.style.marginLeft = "5px"; // Add some space to the left of the button // Add any additional styles to match the search bar's height or other styling const formContainer = document.createElement("div"); formContainer.id = "advancedSearchFormContainer"; document.body.appendChild(formContainer); // const form = document.createElement("form"); formContainer.appendChild(form); const params = { as_q: translation["as_q"][language], as_epq: translation["as_epq"][language], as_oq: translation["as_oq"][language], as_eq: translation["as_eq"][language], as_nlo: translation["as_nlo"][language], as_nhi: translation["as_nhi"][language], // 'lr': translation['lr'][language], // 'cr': translation['cr'][language], as_qdr: { name: translation["as_qdr"][language], options: { "": translation["as_qdr_select"][""][language], d: translation["as_qdr_select"]["d"][language], w: translation["as_qdr_select"]["w"][language], m: translation["as_qdr_select"]["m"][language], y: translation["as_qdr_select"]["y"][language], }, }, as_sitesearch: translation["as_sitesearch"][language], as_occt: { name: translation["as_occt"][language], options: { "": translation["as_occt_select"][""][language], title: translation["as_occt_select"]["title"][language], body: translation["as_occt_select"]["body"][language], url: translation["as_occt_select"]["url"][language], links: translation["as_occt_select"]["links"][language], }, }, as_filetype: translation["as_filetype"][language], // 'tbs': translation['tbs'][language], }; for (const param in params) { if (typeof params[param] === "object") { const label = document.createElement("label"); label.textContent = params[param].name; const select = document.createElement("select"); select.name = param; Object.keys(params[param]["options"]).forEach((option) => { const optionElement = document.createElement("option"); optionElement.value = option; optionElement.textContent = params[param]["options"][option]; select.appendChild(optionElement); }); form.appendChild(label); form.appendChild(select); form.appendChild(document.createElement("br")); continue; } const label = document.createElement("label"); label.textContent = params[param]; const input = document.createElement("input"); input.name = param; input.type = "text"; form.appendChild(label); form.appendChild(input); form.appendChild(document.createElement("br")); } const searchButton = document.createElement("button"); searchButton.textContent = translation["search"][language]; form.appendChild(searchButton); // Add a clear button to reset the form const clearButton = document.createElement("button"); clearButton.textContent = translation["clear"][language]; clearButton.addEventListener("click", function (event) { event.preventDefault(); form.reset(); }); form.appendChild(clearButton); // Load saved data and fill the form when opening a new page window.addEventListener("load", function () { for (const param in params) { const savedValue = GM_getValue(param); if (savedValue) { form[param].value = savedValue; } } }); // Save form data to Greasemonkey storage form.addEventListener("input", function () { for (const param in params) { GM_setValue(param, form[param].value); } }); // Toggle the form display toggleButton.addEventListener("click", function (event) { event.preventDefault(); let status = formContainer.style.display; status = status === "none" || status === "" ? "block" : "none"; formContainer.style.display = status; }); // Submit the form form.addEventListener("submit", function (event) { event.preventDefault(); const searchParams = new URLSearchParams(); for (const param in params) { const value = form[param].value; if (value) { searchParams.set(param, value); } } const searchUrl = "https://www.google.com/search?" + searchParams.toString(); window.location.href = searchUrl; }); })();