On page load intercepts focus stealing and redirects to a custom search bar.
// ==UserScript==
// @name Focus Shield
// @namespace http://tampermonkey.net/
// @version 175
// @description On page load intercepts focus stealing and redirects to a custom search bar.
// @description To use, update the @match line in the script header with your specific SSO domain.
// @author Rick Zabel
// @license CC-BY-NC-SA-4.0
// @match *://sso.yourdomain.com/*
// @icon data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTEyIDFMMyA1djZjMCA1LjU1IDMuODQgMTAuNzQgOSAxMiA1LjE2LTEuMjYgOS02LjQ1IDktMTJWNWwtOS00eiIgZmlsbD0iIzVmNjM2OCIvPjx0ZXh0IHg9IjEyIiB5PSIxNS41IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjZmZmZmZmIiBzdHlsZT0iZm9udC1zaXplOjEycHg7Zm9udC13ZWlnaHQ6Ym9sZDtmb250LWZhbWlseTpBcmlhbCI+RjwvdGV4dD48L3N2Zz4=
// @grant none
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
const SCRIPT_VERSION = "v175";
const initializeFocusShield = () => {
// AI-generated with assistance from Gemini 3 Flash based on concepts by Rick Zabel.
let blockCount = parseInt(localStorage.getItem('focusBlockCount') || '0', 10);
let historyData = JSON.parse(localStorage.getItem('shieldHistory') || '[]');
let sortPreference = localStorage.getItem('shieldSortPref') || 'recent';
const labelText = "Blocked: ";
const greasyForkUrl = "https://greasyfork.org/en/users/5920-rickzabel?sort=updated";
const standardGrey = '#5f6368';
const ghostGrey = '#9aa0a6';
const textDarkGrey = '#3c4043';
const metricGrey = '#70757a';
const glowStyle = 'drop-shadow(0 0 4px rgba(217, 48, 37, 0.6))';
const urlShortcuts = {
"drive": "drive.google.com", "mail": "mail.google.com", "gmail": "mail.google.com",
"cal": "calendar.google.com", "maps": "maps.google.com",
"news": "news.google.com", "docs": "docs.google.com", "sheets": "sheets.google.com",
"slides": "slides.google.com", "keep": "keep.google.com",
"photos": "photos.google.com"
};
let isLocked = true;
let searchWrapper, searchInput, counterDisplay, shieldLink, hoverCard;
let historyDropdown, historyListContainer, sortLabel, clearHistoryBtn;
let ghostMirror, typedSpan, suggestSpan, clearIcon;
let currentSuggestion = "";
let hideTimer, confirmTimer;
let dropdownManuallyOpened = false;
const saveHistory = (term) => {
if (!term) { return; }
const existing = historyData.find((i) => { return i.term.toLowerCase() === term.toLowerCase(); });
if (existing) {
existing.count++;
existing.time = Date.now();
} else {
historyData.push({ term, count: 1, time: Date.now() });
}
localStorage.setItem('shieldHistory', JSON.stringify(historyData));
};
const deleteHistoryItem = (term) => {
historyData = historyData.filter((i) => { return i.term !== term; });
localStorage.setItem('shieldHistory', JSON.stringify(historyData));
renderHistory(searchInput.value);
};
const renderHistory = (filter = "") => {
if (!historyListContainer) { return; }
historyListContainer.textContent = '';
let displayList = historyData.filter((item) => { return item.term.toLowerCase().includes(filter.toLowerCase()); });
if (displayList.length === 0) {
const empty = document.createElement('div');
empty.style.cssText = 'font-size:12px; color:#9aa0a6; text-align:center; padding:10px; font-family:Arial;';
empty.textContent = filter ? 'No matches' : 'No history';
historyListContainer.appendChild(empty);
if (dropdownFooter) { dropdownFooter.style.display = 'none'; }
return;
}
if (dropdownFooter) { dropdownFooter.style.display = 'flex'; }
if (sortPreference === 'recent') {
displayList.sort((a, b) => { return b.time - a.time; });
if (sortLabel) { sortLabel.textContent = 'Sort: Recent'; }
} else {
displayList.sort((a, b) => { return b.count - a.count; });
if (sortLabel) { sortLabel.textContent = 'Sort: Popular'; }
}
displayList.slice(0, 8).forEach((item) => {
const row = document.createElement('div');
row.style.cssText = `display:flex; justify-content:space-between; align-items:center; padding:0 15px 0 0; cursor:pointer; font-size:14px; color:${textDarkGrey}; transition:background 0.1s; font-family:Arial; position:relative; min-height:38px;`;
const textWrapper = document.createElement('div');
textWrapper.style.cssText = 'flex:1; display:flex; align-items:center; padding:8px 0 8px 52px; overflow:hidden;';
row.addEventListener('mouseenter', () => { row.style.background = '#f1f3f4'; });
row.addEventListener('mouseleave', () => { row.style.background = 'transparent'; });
const textPart = document.createElement('span');
textPart.textContent = item.term;
textPart.style.cssText = 'white-space:nowrap; overflow:hidden; text-overflow:ellipsis;';
textWrapper.appendChild(textPart);
const metaGroup = document.createElement('div');
metaGroup.style.cssText = 'display:flex; align-items:center; gap:10px; flex-shrink:0; padding-left:10px;';
const badge = document.createElement('span');
badge.textContent = `${item.count}x`;
badge.style.cssText = `color:${metricGrey}; font-size:11px; font-weight:500;`;
const deleteBtn = document.createElement('span');
deleteBtn.textContent = '✕';
deleteBtn.style.cssText = `color:${metricGrey}; font-size:10px; width:22px; height:22px; display:flex; align-items:center; justify-content:center; border-radius:50%; transition: all 0.15s ease; background: rgba(0, 0, 0, 0.03);`;
deleteBtn.addEventListener('mouseenter', (e) => {
e.stopPropagation();
deleteBtn.style.background = 'rgba(217, 48, 37, 0.15)';
deleteBtn.style.color = '#d93025';
});
deleteBtn.addEventListener('mouseleave', () => {
deleteBtn.style.background = 'rgba(0, 0, 0, 0.03)';
deleteBtn.style.color = metricGrey;
});
deleteBtn.addEventListener('mousedown', (e) => {
e.preventDefault(); e.stopPropagation();
deleteHistoryItem(item.term);
});
metaGroup.appendChild(badge);
metaGroup.appendChild(deleteBtn);
row.appendChild(textWrapper);
row.appendChild(metaGroup);
row.addEventListener('mousedown', (e) => {
if (e.target !== deleteBtn) {
e.preventDefault();
searchInput.value = item.term;
performSearch(item.term, false);
}
});
historyListContainer.appendChild(row);
});
};
const performSearch = (term, isCtrl) => {
let finalTerm = term.trim();
if (!finalTerm) { return; }
const hasProtocol = /^(http|https):\/\//i.test(finalTerm);
const hasWWW = /^www\./i.test(finalTerm);
const hasTLD = /\.(com|net|org|edu|gov|io|co|info)$/i.test(finalTerm);
if (isCtrl) {
let cleanUrl = finalTerm.replace(/\s+/g, '');
if (!hasWWW && !hasProtocol) { cleanUrl = "www." + cleanUrl; }
if (!hasTLD) { cleanUrl = cleanUrl + ".com"; }
finalTerm = cleanUrl;
saveHistory(finalTerm);
window.location.href = hasProtocol ? finalTerm : `http://${finalTerm}`;
} else {
saveHistory(finalTerm);
if (hasProtocol) {
window.location.href = finalTerm;
} else if ((hasWWW || hasTLD) && !finalTerm.includes(' ')) {
window.location.href = `https://${finalTerm}`;
} else {
window.location.href = `https://www.google.com/search?q=${encodeURIComponent(finalTerm)}`;
}
}
renderHistory("");
};
const updateGhostPosition = (fullText) => {
const val = searchInput.value;
if (fullText && fullText.toLowerCase().startsWith(val.toLowerCase()) && val.length > 0) {
currentSuggestion = fullText;
typedSpan.textContent = val;
suggestSpan.textContent = fullText.substring(val.length);
} else {
currentSuggestion = "";
typedSpan.textContent = "";
suggestSpan.textContent = "";
}
};
window.shieldSuggest = (data) => {
if (currentSuggestion && Object.values(urlShortcuts).includes(currentSuggestion)) { return; }
if (!data || !data[1] || data[1].length === 0) { updateGhostPosition(""); return; }
updateGhostPosition(data[1][0]);
};
const fetchPredictive = (term) => {
const lowTerm = term.toLowerCase();
if (urlShortcuts[lowTerm]) { updateGhostPosition(urlShortcuts[lowTerm]); return; }
const oldScript = document.getElementById('shield-jsonp');
if (oldScript) { oldScript.remove(); }
if (!term) { updateGhostPosition(""); return; }
const script = document.createElement('script');
script.id = 'shield-jsonp';
script.src = `https://suggestqueries.google.com/complete/search?client=chrome&q=${encodeURIComponent(term)}&callback=shieldSuggest`;
document.head.appendChild(script);
};
let dropdownFooter;
const drawSearchBar = () => {
if (document.getElementById('gemini-search-wrapper')) { return; }
searchWrapper = document.createElement('div');
searchWrapper.id = 'gemini-search-wrapper';
searchWrapper.style.cssText = 'position:fixed; top:10px; left:850px; width:900px; height:48px; background:#fff; border:1px solid #dadce0; border-radius:24px; display:flex; align-items:center; padding:0 16px; box-sizing:border-box; z-index:2147483647; box-shadow:0 1px 6px rgba(32,33,36,0.28); transition: border-radius 0.2s;';
const inputContainer = document.createElement('div');
inputContainer.style.cssText = 'position:relative; flex:1; display:flex; align-items:center; height:100%; font-family:Arial,sans-serif; font-size:16px;';
ghostMirror = document.createElement('div');
ghostMirror.style.cssText = 'position:absolute; top:0; left:0; width:100%; height:100%; display:flex; align-items:center; pointer-events:none; white-space:pre; z-index:0; padding-left:2px;';
typedSpan = document.createElement('span'); typedSpan.style.color = 'transparent';
suggestSpan = document.createElement('span'); suggestSpan.style.cssText = `color:${ghostGrey}; text-shadow: 0 0 0.1px rgba(0,0,0,0.1);`;
ghostMirror.appendChild(typedSpan); ghostMirror.appendChild(suggestSpan);
searchInput = document.createElement('input');
searchInput.type = 'text';
searchInput.placeholder = isLocked ? 'Search Google' : 'Search Google (Unlocked)';
searchInput.style.cssText = `width:100%; border:none; outline:none; font-size:16px; color:${textDarkGrey}; font-family:Arial,sans-serif; background:transparent; z-index:1; padding-right:35px; padding-left:2px;`;
clearIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
clearIcon.setAttribute('viewBox', '0 0 24 24'); clearIcon.setAttribute('width', '20px'); clearIcon.setAttribute('height', '20px');
clearIcon.style.cssText = 'position:absolute; right:5px; cursor:pointer; fill:#d93025; display:none; z-index:2; transition: transform 0.1s ease, background 0.2s ease; border-radius: 50%; padding: 2px; background: rgba(217, 48, 37, 0.1);';
const clearPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
clearPath.setAttribute('d', 'M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z');
clearIcon.appendChild(clearPath);
clearIcon.addEventListener('mouseenter', () => { clearIcon.style.transform = 'scale(1.15)'; clearIcon.style.background = 'rgba(217, 48, 37, 0.25)'; });
clearIcon.addEventListener('mouseleave', () => { clearIcon.style.transform = 'scale(1)'; clearIcon.style.background = 'rgba(217, 48, 37, 0.1)'; });
clearIcon.addEventListener('click', () => { searchInput.value = ""; clearIcon.style.display = 'none'; updateGhostPosition(""); renderHistory(""); searchInput.focus(); });
inputContainer.appendChild(ghostMirror); inputContainer.appendChild(searchInput); inputContainer.appendChild(clearIcon);
const searchIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
searchIcon.setAttribute('viewBox', '0 0 24 24'); searchIcon.setAttribute('width', '20px'); searchIcon.setAttribute('height', '20px');
searchIcon.style.cssText = 'fill:#5f6368; margin-right:12px; cursor:pointer; flex-shrink:0; transition: transform 0.1s ease;';
const searchPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
searchPath.setAttribute('d', 'M15.5 14h-.79l-.28-.27A6.471 6.471 0 0 0 16 9.5 6.5 6.5 0 1 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z');
searchIcon.appendChild(searchPath);
searchIcon.addEventListener('mouseenter', () => { searchIcon.style.transform = 'scale(1.15)'; });
searchIcon.addEventListener('mouseleave', () => { searchIcon.style.transform = 'scale(1)'; });
searchIcon.addEventListener('click', () => { performSearch(searchInput.value, false); });
const logoGroup = document.createElement('div');
logoGroup.style.cssText = 'display:flex; align-items:center; margin-left:10px; padding-left:10px; border-left:1px solid #dadce0; flex-shrink:0;';
shieldLink = document.createElement('div');
shieldLink.style.cssText = 'display:flex; cursor:pointer; transition:filter 0.2s ease;';
const shieldSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
shieldSvg.setAttribute('viewBox', '0 0 24 24'); shieldSvg.setAttribute('width', '22px'); shieldSvg.setAttribute('height', '22px'); shieldSvg.style.marginRight = '6px';
const shieldPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
shieldPath.setAttribute('d', 'M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4z'); shieldPath.setAttribute('fill', standardGrey);
const logoText = document.createElementNS('http://www.w3.org/2000/svg', 'text');
logoText.setAttribute('x', '12'); logoText.setAttribute('y', '15.5'); logoText.setAttribute('text-anchor', 'middle'); logoText.setAttribute('fill', '#fff');
logoText.style.cssText = 'font-size:12px; font-weight:bold; font-family:Arial,sans-serif; pointer-events:none;'; logoText.textContent = 'F';
shieldSvg.appendChild(shieldPath); shieldSvg.appendChild(logoText); shieldLink.appendChild(shieldSvg);
historyDropdown = document.createElement('div');
// 898px + 2px borders = 900px total width. Left -1px aligns borders perfectly.
historyDropdown.style.cssText = 'position:absolute; top:47px; left:-1px; width:898px; background:#fff; border:1px solid #dadce0; border-top:none; border-radius:0 0 24px 24px; box-shadow:0 4px 6px rgba(32,33,36,0.28); display:none; flex-direction:column; padding:0; z-index:2147483646; overflow:hidden;';
historyListContainer = document.createElement('div');
historyListContainer.style.cssText = 'padding:4px 0;';
dropdownFooter = document.createElement('div');
dropdownFooter.style.cssText = 'display:flex; justify-content:space-between; align-items:center; padding:8px 15px; border-top:1px solid #eee; background:#fafafa; font-family:Arial;';
const sortControl = document.createElement('div');
sortControl.style.cssText = 'display:flex; align-items:center; cursor:pointer; gap:4px; padding:4px 8px; border-radius:4px; background:#f8f9fa; transition: background 0.2s;';
sortControl.addEventListener('mouseenter', () => { sortControl.style.background = '#f1f3f4'; });
sortControl.addEventListener('mouseleave', () => { sortControl.style.background = '#f8f9fa'; });
const sortIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
sortIcon.setAttribute('viewBox', '0 0 24 24'); sortIcon.setAttribute('width', '14px'); sortIcon.setAttribute('height', '14px');
sortIcon.style.fill = '#5f6368';
const sortPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
sortPath.setAttribute('d', 'M3 18h6v-2H3v2zM3 6v2h18V6H3zm0 7h12v-2H3v2z');
sortIcon.appendChild(sortPath);
sortLabel = document.createElement('span');
sortLabel.style.cssText = 'font-size:11px; color:#5f6368; font-weight:500;';
sortLabel.textContent = sortPreference === 'recent' ? 'Sort: Recent' : 'Sort: Popular';
sortControl.appendChild(sortIcon); sortControl.appendChild(sortLabel);
sortControl.addEventListener('mousedown', (e) => {
e.preventDefault();
sortPreference = sortPreference === 'recent' ? 'popular' : 'recent';
localStorage.setItem('shieldSortPref', sortPreference);
renderHistory(searchInput.value);
});
clearHistoryBtn = document.createElement('div');
clearHistoryBtn.style.cssText = 'font-size:11px; color:#d93025; cursor:pointer; font-weight:500; transition: color 0.1s;';
clearHistoryBtn.textContent = 'Clear History';
clearHistoryBtn.addEventListener('mouseenter', () => {
clearHistoryBtn.style.color = '#a50e0e';
clearHistoryBtn.style.textDecoration = 'underline';
});
clearHistoryBtn.addEventListener('mouseleave', () => {
clearHistoryBtn.style.color = '#d93025';
clearHistoryBtn.style.textDecoration = 'none';
});
clearHistoryBtn.addEventListener('mousedown', (e) => {
e.preventDefault();
if (clearHistoryBtn.textContent === 'Clear History') {
clearHistoryBtn.textContent = 'Confirm?';
confirmTimer = setTimeout(() => { clearHistoryBtn.textContent = 'Clear History'; }, 3000);
} else {
historyData = [];
localStorage.setItem('shieldHistory', '[]');
renderHistory("");
clearHistoryBtn.textContent = 'Cleared';
setTimeout(() => { clearHistoryBtn.textContent = 'Clear History'; }, 1000);
}
});
dropdownFooter.appendChild(sortControl); dropdownFooter.appendChild(clearHistoryBtn);
historyDropdown.appendChild(historyListContainer); historyDropdown.appendChild(dropdownFooter);
counterDisplay = document.createElement('span');
counterDisplay.style.cssText = `color:${metricGrey}; font-size:12px; white-space:nowrap; font-family:monospace;`;
counterDisplay.textContent = `${labelText}${blockCount}`;
logoGroup.appendChild(shieldLink); logoGroup.appendChild(counterDisplay);
searchWrapper.appendChild(searchIcon); searchWrapper.appendChild(inputContainer); searchWrapper.appendChild(logoGroup);
searchWrapper.appendChild(historyDropdown);
document.body.appendChild(searchWrapper);
hoverCard = document.createElement('div');
hoverCard.style.cssText = 'position:fixed; top:65px; left:1410px; width:320px; background:#fff; border:1px solid #dadce0; border-radius:12px; box-shadow:0 8px 24px rgba(0,0,0,0.18); padding:16px; display:none; z-index:2147483647; font-family:Arial,sans-serif;';
const cardIcon = shieldSvg.cloneNode(true); cardIcon.setAttribute('width', '66px'); cardIcon.setAttribute('height', '66px'); cardIcon.style.marginRight = '20px';
const cardText = document.createElement('div');
const titleRow = document.createElement('div'); titleRow.style.cssText = 'font-weight:bold; font-size:18px; color:#202124;'; titleRow.textContent = 'Focus Shield';
const creditRow = document.createElement('div'); creditRow.style.cssText = 'font-size:13px; color:#5f6368; margin-top:2px;'; creditRow.textContent = 'by Rick Zabel via Gemini';
const versionRow = document.createElement('div'); versionRow.style.cssText = 'font-size:11px; color:#9aa0a6; margin-top:4px; margin-bottom:10px; font-family:monospace;'; versionRow.textContent = `Version: ${SCRIPT_VERSION}`;
const gfLink = document.createElement('a'); gfLink.href = greasyForkUrl; gfLink.target = '_blank'; gfLink.style.cssText = 'font-size:13px; color:#1a73e8; font-weight:500; text-decoration:none;'; gfLink.textContent = 'Visit Greasy Fork Profile';
cardText.appendChild(titleRow); cardText.appendChild(creditRow); cardText.appendChild(versionRow); cardText.appendChild(gfLink);
const cardFlex = document.createElement('div'); cardFlex.style.display = 'flex'; cardFlex.style.alignItems = 'center';
cardFlex.appendChild(cardIcon); cardFlex.appendChild(cardText); hoverCard.appendChild(cardFlex);
document.body.appendChild(hoverCard);
const syncUI = () => {
if (searchInput && clearIcon) {
clearIcon.style.display = searchInput.value.length > 0 ? 'block' : 'none';
}
};
syncUI();
setInterval(syncUI, 500);
window.addEventListener('pageshow', () => {
syncUI();
if (searchInput && searchInput.value.length > 0 && dropdownManuallyOpened) {
renderHistory(searchInput.value);
}
});
shieldLink.addEventListener('mouseenter', () => { clearTimeout(hideTimer); hoverCard.style.display = 'block'; });
shieldLink.addEventListener('mouseleave', () => { hideTimer = setTimeout(() => { hoverCard.style.display = 'none'; }, 350); });
hoverCard.addEventListener('mouseenter', () => { clearTimeout(hideTimer); });
hoverCard.addEventListener('mouseleave', () => { hideTimer = setTimeout(() => { hoverCard.style.display = 'none'; }, 350); });
searchInput.addEventListener('mousedown', () => {
dropdownManuallyOpened = true;
historyDropdown.style.display = 'flex';
searchWrapper.style.borderRadius = '24px 24px 0 0';
renderHistory(searchInput.value);
});
searchInput.addEventListener('blur', () => {
setTimeout(() => {
dropdownManuallyOpened = false;
historyDropdown.style.display = 'none';
searchWrapper.style.borderRadius = '24px';
}, 200);
});
searchInput.addEventListener('input', () => {
syncUI();
if (dropdownManuallyOpened) { renderHistory(searchInput.value); }
fetchPredictive(searchInput.value);
});
searchInput.addEventListener('keydown', (e) => {
if (e.key === 'Tab' && currentSuggestion !== "") {
e.preventDefault(); searchInput.value = currentSuggestion; updateGhostPosition("");
}
if (e.key === 'Enter') {
performSearch(searchInput.value, e.ctrlKey);
}
});
};
const enforceFocus = () => {
if (isLocked && searchInput && document.activeElement !== searchInput) {
searchInput.focus(); searchInput.select();
}
requestAnimationFrame(enforceFocus);
};
const updateCounter = () => {
blockCount++; localStorage.setItem('focusBlockCount', blockCount.toString());
if (counterDisplay) { counterDisplay.textContent = `${labelText}${blockCount}`; }
if (shieldLink) { shieldLink.style.filter = glowStyle; setTimeout(() => { shieldLink.style.filter = 'none'; }, 200); }
};
const unlock = () => {
isLocked = false;
if (searchWrapper) { searchWrapper.style.backgroundColor = '#f8f9fa'; }
if (searchInput) { searchInput.placeholder = 'Search Google (Unlocked)'; }
};
window.addEventListener('mousedown', (e) => { if (searchWrapper && !searchWrapper.contains(e.target) && !hoverCard.contains(e.target)) { unlock(); } }, true);
window.addEventListener('keydown', (e) => { if (e.key === 'Escape') { unlock(); } });
const domObserver = new MutationObserver(() => {
if (document.body && !document.getElementById('gemini-search-wrapper')) {
drawSearchBar();
}
});
domObserver.observe(document.documentElement, { childList: true, subtree: true });
HTMLElement.prototype.focus = function() {
if (isLocked && this !== searchInput) {
updateCounter();
}
};
if (document.body) { drawSearchBar(); enforceFocus(); }
else { window.addEventListener('DOMContentLoaded', () => { drawSearchBar(); enforceFocus(); }); }
};
initializeFocusShield();
})();