Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==UserScript==
- // @name Vimium Highlight All Elements - Complete Coverage
- // @namespace http://tampermonkey.net/
- // @version 3.0
- // @description Highlight text in ALL elements throughout the document
- // @author You
- // @match *://*/*
- // @grant none
- // ==/UserScript==
- (function() {
- 'use strict';
- const style = document.createElement('style');
- style.textContent = `
- .vimium-highlight {
- background-color: #ffff00 !important;
- color: #000000 !important;
- font-weight: bold !important;
- padding: 0px 1px !important;
- border-radius: 2px !important;
- box-shadow: 0 0 2px rgba(0,0,0,0.2) !important;
- display: inline !important;
- }
- .vimium-notification {
- position: fixed;
- top: 20px;
- right: 20px;
- background: #333;
- color: white;
- padding: 8px 12px;
- border-radius: 4px;
- z-index: 10000;
- font-family: -apple-system, BlinkMacSystemFont, sans-serif;
- font-size: 13px;
- box-shadow: 0 3px 10px rgba(0,0,0,0.3);
- transition: opacity 0.3s ease;
- }
- /* Special styling for different element types */
- title .vimium-highlight {
- /* Title tag highlights */
- background-color: #ff9999 !important;
- }
- input .vimium-highlight {
- /* Input value highlights */
- background-color: #99ff99 !important;
- }
- `;
- document.head.appendChild(style);
- function escapeRegExp(string) {
- return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
- }
- function highlightAllMatches(searchTerm) {
- clearHighlights();
- if (!searchTerm.trim()) return;
- const searchLower = searchTerm.toLowerCase();
- // FIXED: Scan entire document, not just body
- const walker = document.createTreeWalker(
- document.documentElement, // Scan entire document including <head>
- NodeFilter.SHOW_TEXT,
- {
- acceptNode: function(node) {
- // Skip already highlighted content
- if (node.parentElement?.classList?.contains('vimium-highlight')) {
- return NodeFilter.FILTER_REJECT;
- }
- // IMPROVED: Only exclude truly problematic elements
- const parentTag = node.parentElement?.tagName?.toLowerCase();
- // Only skip script and style - allow everything else
- if (['script', 'style'].includes(parentTag)) {
- return NodeFilter.FILTER_REJECT;
- }
- // IMPROVED: Check if element is visible (optional - can be disabled)
- const parent = node.parentElement;
- if (parent) {
- const style = window.getComputedStyle(parent);
- // Skip completely hidden elements
- if (style.display === 'none' || style.visibility === 'hidden') {
- return NodeFilter.FILTER_REJECT;
- }
- }
- // Accept if text contains search term
- return node.textContent.toLowerCase().includes(searchLower) ?
- NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
- }
- },
- false
- );
- const textNodes = [];
- let node;
- while (node = walker.nextNode()) {
- textNodes.push(node);
- }
- // IMPROVED: Also handle form element values
- handleFormElements(searchTerm);
- // IMPROVED: Handle SVG text elements
- handleSVGText(searchTerm);
- // Process regular text nodes
- let processedCount = 0;
- textNodes.forEach(textNode => {
- try {
- if (highlightInTextNode(textNode, searchTerm)) {
- processedCount++;
- }
- } catch (e) {
- console.warn('Error processing text node:', e, textNode);
- }
- });
- const highlightCount = document.querySelectorAll('.vimium-highlight').length;
- const message = `Found ${textNodes.length} text nodes, processed ${processedCount}, highlighted ${highlightCount} matches for "${searchTerm}"`;
- showNotification(highlightCount > 0 ?
- `Highlighted ${highlightCount} matches` :
- `No matches found for "${searchTerm}"`
- );
- console.log(message);
- }
- // NEW: Handle form elements (input, textarea values)
- function handleFormElements(searchTerm) {
- const searchLower = searchTerm.toLowerCase();
- // Handle input elements
- const inputs = document.querySelectorAll('input[type="text"], input[type="search"], input[type="url"], input[type="email"]');
- inputs.forEach(input => {
- if (input.value.toLowerCase().includes(searchLower)) {
- highlightInputValue(input, searchTerm);
- }
- });
- // Handle textarea elements
- const textareas = document.querySelectorAll('textarea');
- textareas.forEach(textarea => {
- if (textarea.value.toLowerCase().includes(searchLower)) {
- highlightTextareaValue(textarea, searchTerm);
- }
- });
- }
- // NEW: Handle SVG text elements
- function handleSVGText(searchTerm) {
- const searchLower = searchTerm.toLowerCase();
- const svgTexts = document.querySelectorAll('text, tspan');
- svgTexts.forEach(svgText => {
- if (svgText.textContent.toLowerCase().includes(searchLower)) {
- // SVG text highlighting is more complex - add a simple background rect
- highlightSVGText(svgText, searchTerm);
- }
- });
- }
- function highlightInputValue(input, searchTerm) {
- // For input elements, we can't directly highlight the value
- // Instead, we add a visual indicator or tooltip
- const searchLower = searchTerm.toLowerCase();
- const value = input.value;
- if (value.toLowerCase().includes(searchLower)) {
- // Add a highlight class to the input
- input.classList.add('vimium-input-highlight');
- // Store original style to restore later
- if (!input.dataset.originalBorder) {
- input.dataset.originalBorder = input.style.border;
- input.dataset.originalBackground = input.style.backgroundColor;
- }
- // Apply highlight styling
- input.style.border = '2px solid #ffff00';
- input.style.backgroundColor = '#ffffcc';
- }
- }
- function highlightTextareaValue(textarea, searchTerm) {
- // Similar to input - highlight the element itself
- const searchLower = searchTerm.toLowerCase();
- const value = textarea.value;
- if (value.toLowerCase().includes(searchLower)) {
- textarea.classList.add('vimium-textarea-highlight');
- if (!textarea.dataset.originalBorder) {
- textarea.dataset.originalBorder = textarea.style.border;
- textarea.dataset.originalBackground = textarea.style.backgroundColor;
- }
- textarea.style.border = '2px solid #ffff00';
- textarea.style.backgroundColor = '#ffffcc';
- }
- }
- function highlightSVGText(svgElement, searchTerm) {
- // For SVG, add a background rect behind the text
- svgElement.classList.add('vimium-svg-highlight');
- // Store original style
- if (!svgElement.dataset.originalFill) {
- svgElement.dataset.originalFill = svgElement.style.fill || '';
- }
- // Apply highlight
- svgElement.style.fill = '#000000';
- // Try to add background (complex for SVG)
- const bbox = svgElement.getBBox();
- const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
- rect.setAttribute('x', bbox.x - 1);
- rect.setAttribute('y', bbox.y - 1);
- rect.setAttribute('width', bbox.width + 2);
- rect.setAttribute('height', bbox.height + 2);
- rect.setAttribute('fill', '#ffff00');
- rect.classList.add('vimium-svg-background');
- svgElement.parentNode.insertBefore(rect, svgElement);
- }
- function highlightInTextNode(textNode, searchTerm) {
- const text = textNode.textContent;
- const parent = textNode.parentNode;
- if (!text || !parent) return false;
- const searchLower = searchTerm.toLowerCase();
- const textLower = text.toLowerCase();
- const parts = [];
- let lastIndex = 0;
- let startIndex = 0;
- let hasMatches = false;
- while ((startIndex = textLower.indexOf(searchLower, lastIndex)) !== -1) {
- hasMatches = true;
- // Add text before match
- if (startIndex > lastIndex) {
- parts.push({
- type: 'text',
- content: text.substring(lastIndex, startIndex)
- });
- }
- // Add matched term
- parts.push({
- type: 'highlight',
- content: text.substring(startIndex, startIndex + searchTerm.length)
- });
- lastIndex = startIndex + searchTerm.length;
- }
- // Add remaining text
- if (lastIndex < text.length) {
- parts.push({
- type: 'text',
- content: text.substring(lastIndex)
- });
- }
- if (hasMatches) {
- const fragment = document.createDocumentFragment();
- parts.forEach(part => {
- if (part.type === 'highlight' && part.content) {
- const mark = document.createElement('mark');
- mark.className = 'vimium-highlight';
- mark.textContent = part.content;
- fragment.appendChild(mark);
- } else if (part.type === 'text' && part.content) {
- fragment.appendChild(document.createTextNode(part.content));
- }
- });
- try {
- parent.replaceChild(fragment, textNode);
- return true;
- } catch (e) {
- console.warn('Error replacing text node:', e);
- return false;
- }
- }
- return false;
- }
- function clearHighlights() {
- // Clear regular text highlights
- const highlights = document.querySelectorAll('.vimium-highlight');
- let clearCount = highlights.length;
- highlights.forEach(highlight => {
- const parent = highlight.parentNode;
- if (parent) {
- try {
- parent.replaceChild(document.createTextNode(highlight.textContent), highlight);
- parent.normalize();
- } catch (e) {
- console.warn('Error clearing highlight:', e);
- }
- }
- });
- // Clear form element highlights
- const inputHighlights = document.querySelectorAll('.vimium-input-highlight');
- inputHighlights.forEach(input => {
- input.classList.remove('vimium-input-highlight');
- if (input.dataset.originalBorder !== undefined) {
- input.style.border = input.dataset.originalBorder;
- input.style.backgroundColor = input.dataset.originalBackground;
- delete input.dataset.originalBorder;
- delete input.dataset.originalBackground;
- }
- });
- const textareaHighlights = document.querySelectorAll('.vimium-textarea-highlight');
- textareaHighlights.forEach(textarea => {
- textarea.classList.remove('vimium-textarea-highlight');
- if (textarea.dataset.originalBorder !== undefined) {
- textarea.style.border = textarea.dataset.originalBorder;
- textarea.style.backgroundColor = textarea.dataset.originalBackground;
- delete textarea.dataset.originalBorder;
- delete textarea.dataset.originalBackground;
- }
- });
- // Clear SVG highlights
- const svgHighlights = document.querySelectorAll('.vimium-svg-highlight');
- svgHighlights.forEach(svg => {
- svg.classList.remove('vimium-svg-highlight');
- if (svg.dataset.originalFill !== undefined) {
- svg.style.fill = svg.dataset.originalFill;
- delete svg.dataset.originalFill;
- }
- });
- const svgBackgrounds = document.querySelectorAll('.vimium-svg-background');
- svgBackgrounds.forEach(bg => bg.remove());
- if (clearCount > 0 || inputHighlights.length > 0 || textareaHighlights.length > 0 || svgHighlights.length > 0) {
- const totalCleared = clearCount + inputHighlights.length + textareaHighlights.length + svgHighlights.length;
- showNotification(`Cleared ${totalCleared} highlights`);
- }
- }
- function showNotification(message) {
- const existing = document.querySelector('.vimium-notification');
- if (existing) existing.remove();
- const notification = document.createElement('div');
- notification.className = 'vimium-notification';
- notification.textContent = message;
- document.body.appendChild(notification);
- setTimeout(() => {
- if (notification.parentNode) {
- notification.style.opacity = '0';
- setTimeout(() => {
- if (notification.parentNode) {
- notification.remove();
- }
- }, 300);
- }
- }, 3000);
- }
- // IMPROVED: Debug function to show what elements are being scanned
- function debugElementScan(searchTerm) {
- const searchLower = searchTerm.toLowerCase();
- const results = {
- textNodes: 0,
- inputElements: 0,
- svgElements: 0,
- hiddenElements: 0,
- matchingNodes: 0
- };
- // Scan all text nodes
- const walker = document.createTreeWalker(
- document.documentElement,
- NodeFilter.SHOW_TEXT,
- {
- acceptNode: function(node) {
- results.textNodes++;
- if (node.parentElement?.classList?.contains('vimium-highlight')) {
- return NodeFilter.FILTER_REJECT;
- }
- const parentTag = node.parentElement?.tagName?.toLowerCase();
- if (['script', 'style'].includes(parentTag)) {
- return NodeFilter.FILTER_REJECT;
- }
- const parent = node.parentElement;
- if (parent) {
- const style = window.getComputedStyle(parent);
- if (style.display === 'none' || style.visibility === 'hidden') {
- results.hiddenElements++;
- return NodeFilter.FILTER_REJECT;
- }
- }
- if (node.textContent.toLowerCase().includes(searchLower)) {
- results.matchingNodes++;
- console.log('Matching text node:', {
- text: node.textContent.substring(0, 50),
- parent: node.parentElement?.tagName,
- parentClass: node.parentElement?.className
- });
- return NodeFilter.FILTER_ACCEPT;
- }
- return NodeFilter.FILTER_REJECT;
- }
- },
- false
- );
- while (walker.nextNode()) {
- // Just iterate to trigger acceptNode
- }
- // Check form elements
- const allInputs = document.querySelectorAll('input, textarea');
- allInputs.forEach(input => {
- results.inputElements++;
- if (input.value && input.value.toLowerCase().includes(searchLower)) {
- console.log('Matching form element:', {
- type: input.tagName,
- value: input.value.substring(0, 50),
- id: input.id,
- name: input.name
- });
- }
- });
- // Check SVG elements
- const allSVG = document.querySelectorAll('text, tspan');
- allSVG.forEach(svg => {
- results.svgElements++;
- if (svg.textContent.toLowerCase().includes(searchLower)) {
- console.log('Matching SVG element:', {
- text: svg.textContent,
- tag: svg.tagName
- });
- }
- });
- console.log('Debug scan results:', results);
- showNotification(`Debug: ${results.textNodes} text nodes, ${results.matchingNodes} matches, ${results.inputElements} form elements, ${results.svgElements} SVG elements`);
- }
- // Keyboard bindings
- document.addEventListener('keydown', function(e) {
- if (e.ctrlKey && e.shiftKey && e.key === 'H') {
- e.preventDefault();
- e.stopPropagation();
- const searchTerm = prompt('Highlight all occurrences (searches entire document):');
- if (searchTerm !== null) {
- if (searchTerm.trim()) {
- highlightAllMatches(searchTerm);
- } else {
- clearHighlights();
- }
- }
- }
- if (e.ctrlKey && e.shiftKey && e.key === 'C') {
- e.preventDefault();
- e.stopPropagation();
- clearHighlights();
- }
- // DEBUG: Ctrl+Shift+D for debug scan
- if (e.ctrlKey && e.shiftKey && e.key === 'D') {
- e.preventDefault();
- e.stopPropagation();
- const searchTerm = prompt('Debug scan for term:');
- if (searchTerm?.trim()) {
- debugElementScan(searchTerm);
- }
- }
- if (e.key === 'Escape') {
- const highlights = document.querySelectorAll('.vimium-highlight, .vimium-input-highlight, .vimium-textarea-highlight, .vimium-svg-highlight');
- if (highlights.length > 0) {
- e.preventDefault();
- e.stopPropagation();
- clearHighlights();
- }
- }
- });
- // Debug utilities
- window.vimiumHighlight = {
- highlight: highlightAllMatches,
- clear: clearHighlights,
- debug: debugElementScan,
- test: function(term) {
- console.log('Testing comprehensive highlight for:', term);
- highlightAllMatches(term);
- }
- };
- })();
Advertisement
Add Comment
Please, Sign In to add comment