您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds useful features for google searching. English support only. Tested on Brave Browser. Intended to work with light mode and dark mode. Doesn't work on mobile view.
当前为
// ==UserScript== // @name Better Google Search // @namespace Better Google Search // @match https://www.google.com/search?* // @grant GM_addStyle // @require https://openuserjs.org/src/libs/sizzle/GM_config.js // @grant GM_getValue // @grant GM_setValue // @version 1.3 // @author kyosukyuu // @description Adds useful features for google searching. English support only. Tested on Brave Browser. Intended to work with light mode and dark mode. Doesn't work on mobile view. // @license MIT // ==/UserScript== GM_addStyle (` .btns--container { display: flex; position: absolute; width: 100%; left: 100%; top: 0; margin-left: 20px; z-index: 1; background: #202124; } .btns--container-light { background: #fff; } .btn { margin-right: 8px; cursor: pointer; } .btn--container { position: relative; padding: 4px; margin: 0 8px; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; -o-user-select: none; user-select: none; } .btn--container-light { color: #70757a !important; } .btn--container:hover { color: #ddd } .btn--container-light:hover { color: #202124 !important; } /* .btn--container:hover .caret-dropdown { border-color: #ddd transparent; } .btn--container-light:hover .caret-dropdown { border-color: #202124 transparent !important; } */ .btn--active { color: #e8eaed !important; } .btn--active-light { color: #202124; } .caret-dropdown--active { border-color: #ddd transparent !important; } .btn--caret::after{ border-color: #9aa0a6 transparent; border-style: solid; border-width: 5px 4px 0 4px; width: 0; height: 0; margin-left: 2px; top: 13px; margin-top: -2px; position: absolute; right: 0; content: " " } .btn--caret:hover::after, .btn--caret:focus::after { border-color: #ddd transparent !important; } .btn--container:hover > .btn--caret::after { border-color: #ddd transparent !important; } .btn--container-light:hover > .btn--caret::after { border-color: #202124 transparent !important; } /* .caret-dropdown { border-color: #9aa0a6 transparent; border-style: solid; border-width: 5px 4px 0 4px; width: 0; height: 0; margin-left: 2px; top: 13px; margin-top: -2px; position: absolute; right: 0; } */ .dropdown--container { z-index: 10; padding: 5px 0; border-radius: 8px; box-shadow: 1px 1px 15px 0px #171717; background-color: #202124; position: absolute; width: 100%; min-width: 80px; max-width: 105px; top: 25px; overflow: hidden; list-style-type: none; } .dropdown--container-light { box-shadow: 0 2px 10px 0 rgb(0 0 0 / 20%); background-color: #fff; } .show { display: block !important; } .hide { display: none; } .dropdown--items { line-height: 16px; padding: 7px 8px; color: #bdc1c6; display: flex; align-items: center; cursor: pointer; margin: auto; } .dropdown--items-light { color: #5f6368; } .dropdown--items:hover, .dropdown--items:focus { background-color: rgba(255,255,255,0.1); } .dropdown--items-light:hover, .dropdown--items-light:focus{ background-color: rgba(0,0,0,0.1) !important; } @media only screen and (max-width: 1450px) { .btns--container { flex-direction: column; max-width: 125px; box-shadow: 1px 1px 3px 2px #0000003b; } .dropdown--container { left: 113px; top: 0; } } `); (() => { "use strict" const fieldDefs = { "bypass-csp": { "section": [GM_config.create("Functional Settings"), "Affects the behavior of the script"], "label": "Bypass CSP", "type": "checkbox", "default": false, }, } GM_config.init({ "id": "settings", "title": "Better Google Search Settings", "fields": fieldDefs, }); const BYPASS_CSP = JSON.parse(GM_getValue("settings"))["bypass-csp"] || false const qSelect = (selector) => document.querySelector(selector) const qSelectAll = (selectors) => document.querySelectorAll(selectors) const qAllCallback = (selector, callback) => Array.from(qSelectAll(selector)).forEach((el, i) => callback(el, i)) let relativeParent = qSelect("input").parentElement.parentElement.parentElement.parentElement // check for theme const getDefaultTheme = () => { if (window?.matchMedia("(prefers-color-scheme: dark)").matches) return true return false }; const isDark = getDefaultTheme(); // bypass content-security-policy (CSP) to allow the script to work on google images // WARNING: this makes innerHTML vulnerable to injection if (window.trustedTypes?.createPolicy && BYPASS_CSP) { relativeParent = qSelect("input").parentElement.parentElement.parentElement window.trustedTypes.createPolicy("default", { createHTML: (string, sink) => string }); } const FILE_TYPE = "FILE_TYPE" const EXCLUDE = "EXCLUDE" const SITE = "SITE" const EXACT_QUERY = "EXACT_QUERY" const TERM_APPEARS = "TERM_APPEARS" const BEFORE = "BEFORE" const AFTER = "AFTER" const SETTINGS = "SETTINGS" // contains all possible search actions you can perform const actions = [ {name: "File Type", action: FILE_TYPE, data: "filetype:", choices: [{name: "PDF", data: "pdf"}, {name: "DOC", data: "doc"}, {name: "DOCX", data: "docx"}, {name: "TXT", data: "txt"}, {name: "LOG", data: "log"}, {name: "PPT", data: "ppt"}, {name: "PPTX", data: "pptx"}, {name: "XML", data: "xml"}, {name: "TORRENT", data: "torrent"}, {name: "RTF", data: "rtf"}]}, {name: "Exclude", action: EXCLUDE, data: "-", isUnique: false}, {name: "Site", action: SITE, data: "site:", choices: [{name: "reddit", data: "reddit.com"}, {name: "stack overflow", data: "stackoverflow.com"}, {name: "youtube", data: "youtube.com"}, {name: "twitter", data: "twitter.com"}, {name: "facebook"}, {name: "custom", data: "facebook.com"}]}, {name: "Exact Query", action: EXACT_QUERY, data: `""`, isUnique: false}, {name: "Term Appears", action: TERM_APPEARS, choices: [{name: "anywhere in page", data: ""}, {name: "in the title of the page", data: "allintitle:"}, {name: "in the text of the page", data: "allintext:"}, {name: "in the URL of the page", data: "allinurl:"}, {name: "in links to the page", data: "allinanchor:"}]}, {name: "Before", action: BEFORE, data: "before:", isUnique: true}, {name: "After", action: AFTER, data: "after:", isUnique: true}, {name: "Settings", action: SETTINGS, isUnique: true} ] const toggleDropdown = (evt) => { if (evt.target !== evt.currentTarget){ evt.currentTarget.lastElementChild.classList.toggle("show") // theme dependent styles if (isDark) { evt.currentTarget.classList.toggle("btn--active") } else{ evt.currentTarget.classList.toggle("btn--active-light") } } } const createButtons = () => { relativeParent.style.position = "relative" const buttonsContainer = document.createElement("section") relativeParent.appendChild(buttonsContainer) buttonsContainer.classList.add("btns--container") actions.forEach((action) => { let caretDropdown = "" let dropdownMenu = "" let hasDropdown = false if (action?.choices) { hasDropdown = true caretDropdown = `<span class="caret-dropdown"></span>` // let parentAction = action.data let dropdownItems = action.choices.map((item) => `<li class="dropdown--items" data-action="${item.data}" data-parent-action="${action.data ? action.data : ""}">${item.name}</li>`).join("") dropdownMenu = ` <ul class="hide dropdown--container"> ${dropdownItems} </ul> ` } if (hasDropdown){ buttonsContainer.innerHTML += ` <section class="btn--container"> <div class="btn">${action.name}</div> ${dropdownMenu} </section> ` } else{ buttonsContainer.innerHTML += ` <section class="btn--container"> <div class="btn">${action.name}</div> </section> ` } }) } createButtons() // attach buttons with dropdown function qAllCallback(".btn--container", (btn) => btn.addEventListener("click", toggleDropdown)) qAllCallback(".dropdown--container", (el) => { el.addEventListener("click", (evt) => evt.stopPropagation()) // add caret to buttons with dropdown el.previousElementSibling.classList.add("btn--caret") }) // close dropdown menus when clicked on somewhere other than the dropdown areas window.onclick = (evt) => { if (!evt.target.matches(".btn")) { qAllCallback(".dropdown--container", ({classList}) => classList.contains("show") && classList.remove("show")) qAllCallback(".btn--active", ({classList}) => classList.remove("btn--active")) } } const attachActions = () => { // attach dropdown items with click handler qAllCallback(".dropdown--items", (item) => { item.addEventListener("click", (evt) => { const parentAction = evt.currentTarget.getAttribute("data-parent-action") const action = evt.currentTarget.getAttribute("data-action") const input = qSelect("input") // check if unused query already exists const expression = new RegExp(`(${parentAction}\\w+\\.\\w+|${parentAction}\\w+|${parentAction})`, "g") if(parentAction && input.value.match(expression)) { input.value = input.value.replace(expression, (search) => `${parentAction}${action}`) if (parentAction === "site:"){ const searchPos = input.value.search(/(site:)/) input.setSelectionRange(searchPos + parentAction.length, searchPos + parentAction.length) } input.focus() return } // remove excess spaces input.value = input.value.replace(/\s{2,}/g, (search) => " ") // apply changes to search bar value input.value += ` ${parentAction}${action} ` // trim and remove excess spaces input.value = input.value.trim().replace(/\s{2,}/g, (search) => " ") // focus on search bar input.focus() }) }) // attach non-having dropdown items with click handler qAllCallback(".btn--container", (el, i) => { if(el.childElementCount === 1) { el.firstElementChild.addEventListener("click", (evt) => { const action = actions[i].data if (actions[i].action === SETTINGS) { GM_config.open() return } const input = qSelect("input") // check if query is unique (only one of it should exist) const queryExists = new RegExp(`${action}`) if(actions[i].isUnique && input.value.match(queryExists)){ const searchPos = input.value.search(queryExists) input.setSelectionRange(searchPos + action.length, searchPos + action.length) input.focus() return } // check if unused query is already in search bar const expression = new RegExp(`(${action}\\W)|(\\W${action}\\B)`, "g") if(input.value.match(expression)){ // set cursor at unused query const searchPos = input.value.search(expression) if(action.length > 2) input.setSelectionRange(searchPos + action.length + 1, searchPos + action.length + 1) else input.setSelectionRange(searchPos + 2, searchPos + 2) } else{ input.value = input.value.trim() // apply changes to search bar value input.value += ` ${action} ` input.value = input.value.trim() } if(action === `""`) { const quotationsPos = input.value.search(`""`) input.setSelectionRange(quotationsPos + 1, quotationsPos + 1) } //focus on search bar input.focus() }) } }) } attachActions() if(!isDark){ qAllCallback(".btns--container", (el) => el.classList.add("btns--container-light")) qAllCallback(".btn--container", (el) => el.classList.add("btn--container-light")) qAllCallback(".dropdown--container", (el) => el.classList.add("dropdown--container-light")) qAllCallback(".dropdown--items", (el) => el.classList.add("dropdown--items-light")) } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址