Last active
May 28, 2023 11:58
-
-
Save harsilspatel/886c37b5a4c0c7de97a2bf1983bd8f7a to your computer and use it in GitHub Desktop.
A Userscript to focus search bar on "/" keypress
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name forward-slash | |
// @namespace harsilspatel | |
// @version 0.7 | |
// @description press "/" to focus on search bar | |
// @author harsilspatel | |
// @match *://*/* | |
// @downloadURL https://gist.github.com/harsilspatel/886c37b5a4c0c7de97a2bf1983bd8f7a/raw/forward-slash.user.js | |
// @updateURL https://gist.github.com/harsilspatel/886c37b5a4c0c7de97a2bf1983bd8f7a/raw/forward-slash.user.js | |
// @icon https://www.google.com/s2/favicons?domain=google.com | |
// @grant none | |
// ==/UserScript== | |
(function () { | |
"use strict"; | |
// https://stackoverflow.com/a/38795917/9701238 | |
const isTextBox = (element) => { | |
console.log("isTextBox", element); | |
const tagName = (element.tagName || "").toLowerCase(); | |
if (tagName === "textarea") return true; | |
const type = (element.getAttribute("type") || "").toLowerCase(), | |
// if any of these input types is not supported by a browser, it will behave as input type text. | |
inputTypes = ["text", "password", "number", "email", "tel", "url", "search", "date", "datetime", "datetime-local", "time", "month", "week"]; | |
if (inputTypes.indexOf(type) >= 0) return true; | |
console.log("element.contentEditable", element.contentEditable === "true", element.getAttribute("role") === "textbox"); | |
return element.contentEditable === "true" || element.getAttribute("role") === "textbox"; | |
}; | |
const isVisible = (element) => !(element.offsetParent === null); | |
const focusInput = (node) => { | |
node.focus(); | |
const length = node.value.length; | |
node.setSelectionRange(length, length); | |
return; | |
}; | |
// source: https://stackoverflow.com/a/7557433/9701238 | |
const isElementInViewport = (el) => { | |
const rect = el.getBoundingClientRect(); | |
return ( | |
rect.top >= 0 && | |
rect.left >= 0 && | |
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) /* or $(window).height() */ && | |
rect.right <= (window.innerWidth || document.documentElement.clientWidth) /* or $(window).width() */ | |
); | |
}; | |
const nonTextInputFields = ["button", "checkbox", "file", "image", "radio", "reset", "submit"]; | |
const querySelectorAllWrapper = (getOnlyViewportElements) => (selector) => | |
Array.from(window.document.querySelectorAll(selector)) | |
.filter(isVisible) | |
.filter((el) => (getOnlyViewportElements ? isElementInViewport(el) : true)) | |
.filter((el) => !nonTextInputFields.includes(el.type)); // we need to filter out buttons and shit | |
const keydownListener = (e) => { | |
// return if user is typing | |
if (e.code !== "Slash" || isTextBox(e.target)) return; | |
e.preventDefault(); | |
// sometimes there are multiple search bars (some of them not in viewport) | |
// by default i want the ones in the viewport | |
// but if i press option + / then it should get me the first search bar | |
const isOptionPressed = e.altKey; | |
const querySelectorAll = querySelectorAllWrapper(!isOptionPressed); | |
const searchInputs = querySelectorAll("[type='search']"); | |
console.log("input[type='search']", searchInputs); | |
if (searchInputs.length === 1) return focusInput(searchInputs[0]); | |
const qInputs = querySelectorAll("[name='q']"); | |
console.log("input[name='q']", qInputs); | |
if (qInputs.length === 1) return focusInput(qInputs[0]); | |
const textInputs = querySelectorAll("input[type='text']"); | |
console.log("input[type='text']", textInputs); | |
if (textInputs.length === 1) return focusInput(textInputs[0]); | |
const filteredTextInputs = textInputs.filter((element) => (element.ariaLabel || "").toLowerCase() === "search"); | |
console.log("filteredTextInputs", filteredTextInputs); | |
if (filteredTextInputs.length === 1) return focusInput(filteredTextInputs[0]); | |
const inputWithSearchPlaceholder = searchInputs.concat(qInputs, textInputs).find((input) => (input.placeholder || "").toLowerCase().includes("search")); | |
console.log("inputWithSearchPlaceholder", inputWithSearchPlaceholder); | |
if (inputWithSearchPlaceholder) return focusInput(inputWithSearchPlaceholder); | |
const inputs = querySelectorAll("input"); | |
console.log("input", inputs); | |
if (inputs.length === 1) return focusInput(inputs[0]); | |
}; | |
console.log("forward-slash script loaded"); | |
window.addEventListener("keypress", keydownListener); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment