您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Vimium Mock
// ==UserScript== // @name VimJ // @namespace VimJ // @version 1.0 // @description Vimium Mock // @author Jim // @require http://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.2.1.slim.min.js // @match *://*/* // @grant GM_openInTab // @run-at document-start // ==/UserScript== (function () { 'use strict'; // Hook Element.prototype._addEventListener = Element.prototype.addEventListener; Element.prototype.addEventListener = function (type, listener, userCapture) { this._addEventListener(type, listener, userCapture); if (this.tagName.match(/^(DIV|I|LI)$/) && type.match(/(mouse|click)/)) { Page.clickElements.push(this); } }; // Event $(window).on('click resize scroll', () => Page.escape()); window ? register() : setTimeout(register, 0); function register() { addEventListener('keydown', (event) => { var isCommand = Page.isCommand(event); var activeElement = document.activeElement; if (event.code === 'Tab' && !tab()) { event.preventDefault(); event.stopImmediatePropagation(); isCommand ? Page.escape() : activeElement && activeElement.blur(); document.body.click(); } else if (isCommand) { event.stopImmediatePropagation(); } function tab() { return activeElement && activeElement.tagName === 'INPUT' && (!activeElement.type || activeElement.type === 'text') && $(activeElement).closest('form').find('input[type="password"]').length; } }, true); addEventListener('keyup', (event) => { if (Page.isCommand(event)) { event.preventDefault(); event.stopImmediatePropagation(); } }, true); addEventListener('keypress', (event) => { if (Page.isCommand(event)) { event.preventDefault(); event.stopImmediatePropagation(); var char = String.fromCharCode(event.keyCode).toUpperCase(); switch (char) { case 'F': $('._hint').length ? Page.match(char) : Page.linkHint(); break; case 'J': Page.scrollTop(200); break; case 'K': Page.scrollTop(-200); break; case ' ': Page.plus(); break; default: Page.match(char); break; } } }, true); } $(`<style> ._plus{font-weight: bold} ._click{ box-shadow: 0 0 1px 1px gray; pointer-events: none; position: absolute; z-index: 2147483648; } ._hint{ background-color: rgba(173, 216, 230, 0.7); border-radius: 3px; box-shadow: 0 0 2px; color: black; font-family: monospace; font-size: 13px; position: fixed; z-index: 2147483648; } </style>`).appendTo('html'); var Page = { clickElements: [], chars: '', hintMap: {}, isPlus: false, linkHint: () => { var elements = getElements(); var hints = getHints(elements); Page.hintMap = popupHints(elements, hints); function getElements() { var elements = $('a, button, select, input, textarea, [role="button"], [contenteditable], [onclick]'); var clickElements = $(Page.clickElements); return purify(elements, clickElements.add(clickElements.find('div')).addClass('_strict')); function purify(elements, clickElements) { var length = 16; var substitutes = []; function isDisplayed(element) { var style = getComputedStyle(element); if (style.opacity === '0' || (element.classList.contains('_strict') && style.cursor.search(/pointer|text/) === -1)) { return; } var rect = element.getClientRects()[0]; if (rect && rect.left >= 0 && rect.top >= 0 && rect.right <= innerWidth && rect.bottom <= innerHeight) { element._left = rect.left; element._top = rect.top; var positions = [[element._left + rect.width / 3, element._top + rect.height / 3], [ Math.min(element._left + rect.width - 1, element._left + length), Math.min(element._top + rect.height - 1, element._top + length) ]]; for (var i = 0; i < positions.length; i++) { var targetElement = document.elementFromPoint(positions[i][0], positions[i][1]); if (targetElement === element || element.contains(targetElement)) { return true; } } if (element.tagName === 'INPUT' && targetElement.tagName !== 'INPUT') { var a = xPath(element); var b = xPath(targetElement); if (a.substr(0, a.lastIndexOf('/')) === b.substr(0, b.lastIndexOf('/'))) { return true; } } else if (element.tagName === 'A') { substitutes.push(element); } } } elements = elements.filter((i, elem) => isDisplayed(elem)); clickElements = clickElements.filter((i, elem) => isDisplayed(elem)); clickElements = clickElements.add($(substitutes).find('> *').filter((i, elem) => isDisplayed(elem))); var xTree = Tree.create(0, innerWidth); var yTree = Tree.create(0, innerHeight); elements = elements.get().reverse().filter(isExclusive); clickElements = clickElements.get().reverse().filter(isExclusive); function isExclusive(element) { var overlapsX = $(); var overlapsY = $(); var leftTo = Math.min(element._left + length, xTree.to); var topTo = Math.min(element._top + length, yTree.to); Tree.search(xTree, element._left, leftTo, x => overlapsX = overlapsX.add(x)); Tree.search(yTree, element._top, topTo, y => overlapsY = overlapsY.add(y)); if (overlapsX.filter(overlapsY).length === 0) { Tree.insert(xTree, element._left, leftTo, element); Tree.insert(yTree, element._top, topTo, element); overlapsY.map((i, elem) => { if (Math.abs(element._top - elem._top) <= 5 && Math.abs(element._left - elem._left) <= innerWidth / 10) { element._top = elem._top; return false; } }); return true; } } return $(elements).add(clickElements); } } function getHints(elements) { var hints = []; var Y = 'ABCDEGHILM'; var X = '1234567890'; var B = 'NOPQRSTUVWXYZ' + Y + X; var lengthB = B.length; var all = {}; for (var i = 0; i < B.length; i++) { all[B.charAt(i)] = B; } for (i = 0; i < elements.length; i++) { var element = elements[i]; var y = Y.charAt(Math.round(element._top / innerHeight * (Y.length - 1))); var x = X.charAt(Math.round(element._left / innerWidth * (X.length - 1))); if (all[y].length === 0) { y = B.charAt(0); } if (!all[y].includes(x)) { x = all[y].charAt(0); } all[y] = all[y].replace(x, ''); if (all[y] === '') { B = B.replace(y, ''); } hints.splice(Math.round(hints.length * 0.618 % 1 * hints.length), 0, y + x); } var availableChars = []; var singletonChars = []; for (i = 0; i < B.length; i++) { var char = B.charAt(i); if (all[char].length === lengthB) { availableChars.push(char); } else if (all[char].length === lengthB - 1) { singletonChars.push(char); } } for (i = 0; i < hints.length; i++) { var startChar = hints[i].charAt(0); if (singletonChars.includes(startChar)) { hints[i] = startChar; } else if (availableChars.length) { hints[i] = availableChars.pop(); if ((all[startChar] += '.').length === lengthB - 1) { singletonChars.push(startChar); } } } var singletonChar; var availableChar = 'F'; for (i = 0; i < elements.length && availableChar === 'F'; i++) { element = elements[i]; if ((element.tagName === 'INPUT' && element.type.search(/(button|checkbox|file|hidden|image|radio|reset|submit)/i) === -1) || element.hasAttribute('contenteditable') || element.tagName === 'TEXTAREA') { var hint = hints[i]; hints[i] = availableChar; availableChar = hint; startChar = hint.charAt(0); if (availableChar.length > 1 && (all[startChar] += '.').length === lengthB - 1) { singletonChar = startChar; } } } for (i = 0; availableChar.length === 1 && i < hints.length; i++) { hint = hints[i]; if (hint.length > 1) { hints[i] = availableChar; availableChar = hint; startChar = hint.charAt(0); if ((all[startChar] += '.').length === lengthB - 1) { singletonChar = startChar; } } } for (i = 0; singletonChar && i < hints.length; i++) { if (hints[i].startsWith(singletonChar)) { hints[i] = singletonChar; break; } } return hints; } function popupHints(elements, hints) { var map = {}; for (var i = 0; i < elements.length; i++) { var element = elements[i]; var hint = hints[i]; map[hint] = element; var style = { top: element._top, left: element._left }; $('<div class="_hint">' + hint + '</div>') .css(style) .appendTo('html'); } return map; } }, escape: () => { $('._hint').remove(); Page.chars = ''; Page.hintMap = {}; Page.isPlus = false; }, match: (char) => { var hints = $('._hint'); if (hints.length) { Page.chars += char; var removeElements = []; hints = hints.filter((i, element) => { if (element.innerText.startsWith(char)) { return element.innerText = element.innerText.substr(-1); } else { removeElements.push(element); } }); $(removeElements).remove(); if (hints.length === 1) { var done; var element = Page.hintMap[Page.chars]; if (Page.isPlus) { if (element.tagName === 'A' && element.href) { done = GM_openInTab(element.href, true); } else { for (var parent of $(element).parentsUntil(document.body)) { if (parent.tagName === 'A' && parent.href) { done = GM_openInTab(parent.href, true); break; } } } } if (!done) { Page.click(element); } var rect = element.getBoundingClientRect(); var style = { width: rect.width, height: rect.height, top: rect.top + window.pageYOffset, left: rect.left + window.pageXOffset, }; $('<div class="_click"></div>') .css(style) .appendTo('html'); setTimeout(() => $('._click').remove(), 500); Page.escape(); } } }, scrollTop: (offset) => { var targets = Array .from(document.querySelectorAll('div')) .filter((elem) => elem.scrollHeight >= elem.clientHeight && getComputedStyle(elem).overflowY !== 'hidden') .sort((a, b) => a.scrollHeight > b.scrollHeight); if (typeof document.activeElement !== typeof document.scrollingElement) { if (document.scrollingElement.tagName.match(/^(DIV|BODY)$/)) targets.push(document.scrollingElement); } else { if (document.activeElement.tagName.match(/^(DIV|BODY)$/)) targets.push(document.activeElement); } for (var i = targets.length - 1; i >= 0; i--) { var target = targets[i]; if ((target.scrollTop += 1) !== 1 || (target.scrollTop += -1) !== -1) { return target.scrollTop += offset; } } scrollBy(0, offset); }, plus: () => { Page.isPlus = !Page.isPlus; $('._hint').toggleClass('_plus'); }, click: (element) => { if ((element.tagName === 'INPUT' && element.type.search(/(button|checkbox|file|hidden|image|radio|reset|submit)/i) === -1) || element.hasAttribute('contenteditable') || element.tagName === 'TEXTAREA') { element.focus(); if (element.setSelectionRange) { try { var len = element.value.length * 2; element.setSelectionRange(len, len); } catch (e) { } } } else if (element.tagName === 'A' || element.tagName === 'INPUT') { element.click(); } else { var names = ['mousedown', 'mouseup', 'click', 'mouseout']; for (var i = 0; i < names.length; i++) { element.dispatchEvent(new MouseEvent(names[i], {bubbles: true})); } } }, isCommand: (event) => { var element = document.activeElement; var isInput = element && !element.hasAttribute('readonly') && element.type !== 'checkbox' && (element.tagName.match(/INPUT|TEXTAREA/) || element.hasAttribute('contenteditable')); var char = String.fromCharCode(event.keyCode).toUpperCase(); var isUseful = $('._hint, ._click').length || 'FJK'.includes(char); return !event.ctrlKey && !isInput && isUseful; } }; var Tree = { create: (from, to) => { return { from: Math.floor(from), to: Math.floor(to) }; }, getLeft: (node) => { if (node.left) { return node.left; } else { return node.left = Tree.create(node.from, Math.floor((node.from + node.to) / 2)); } }, getRight: (node) => { if (node.right) { return node.right; } else { return node.right = Tree.create(Math.floor((node.from + node.to) / 2) + 1, node.to); } }, insert: (node, from, to, value) => { from = Math.floor(from); to = Math.floor(to); if (node.from === from && node.to === to) { if (node.values) { return node.values.push(value); } else { return node.values = [value]; } } var mid = Math.floor((node.from + node.to) / 2); if (from < mid) { Tree.insert(Tree.getLeft(node), from, Math.min(to, mid), value); } if (to > mid) { Tree.insert(Tree.getRight(node), Math.max(from, mid + 1), to, value); } }, search: (node, from, to, outPipe) => { from = Math.floor(from); to = Math.floor(to); if (node.from === from && node.to === to) { return include(node, outPipe); } if (node.values && node.values.length) { outPipe(node.values); } var mid = Math.floor((node.from + node.to) / 2); if (from < mid) { Tree.search(Tree.getLeft(node), from, Math.min(to, mid), outPipe); } if (to > mid) { Tree.search(Tree.getRight(node), Math.max(from, mid + 1), to, outPipe); } function include(node, outPipe) { if (node.values && node.values.length) { outPipe(node.values); } if (node.left) { include(node.left, outPipe); } if (node.right) { include(node.right, outPipe); } } } }; function xPath(node) { if (!(node && node.nodeType === 1)) { return ''; } var count = 0; var siblings = node.parentNode.childNodes; for (var i = 0; i < siblings.length; i++) { var sibling = siblings[i]; if (sibling.tagName === node.tagName) { count += 1; } if (sibling === node) { break; } } var suffix = count > 1 ? '[' + count + ']' : ''; return xPath(node.parentNode) + '/' + node.tagName + suffix; } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址