您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
image popup: zoom, pan, scroll
当前为
- // ==UserScript==
- // @name Hover Zoom Minus --
- // @namespace Hover Zoom Minus --
- // @version 1.0.2
- // @description image popup: zoom, pan, scroll
- // @author Ein, Copilot AI
- // @match *://*/*
- // @license MIT
- // @grant none
- // ==/UserScript==
- // 1. to use hover over the image(container) to view a popup of the target image
- // 2. to zoom in/out use wheel up/down. to reset press the scroll button
- // 3. click left mouse to lock popup this will make it move along with the mouse, click again to release (indicated by green border)
- // 4. while being locked the wheel up/down will act as scroll up/down
- // 5. double click will lock it on screen preventing it from being hidden
- // 6. while locked at screen (indicated by red outline) a single click with the blurred background will unblur it, only one popup per time, so the locked popup will prevent other popup to spawn
- // 7. double clicking on blurred background will de-spawn popup
- // 8. to turn on/off hover at the bottom of the page
- (function() {
- 'use strict';
- // Configuration ----------------------------------------------------------
- // Define regexp of web page you want HoverZoomMinus to run with,
- // 1st array value - default status at start of page: '1' for on, '0' for off
- // 2nd array value - spawn position for popup: 'center' for center of screen, '' for cursor position
- // 3rd array value - allowed interval for spawning popup; i.e. when exited on popup but immediately touches an img container thus making it "blink spawn blink spawn", experiment it with the right number
- const siteConfig = {
- 'reddit.com*': [1, 'center', '0'],
- '9gag.com*': [1, 'center', '0'],
- 'feedly.com*': [1, 'center', '200'],
- '4chan.org*': [1, '', '400'],
- 'deviantart.com*': [0, 'center', '300']
- };
- // image container [hover box where popup triggers]
- const imgContainers = `
- /* ------- reddit */ ._3Oa0THmZ3f5iZXAQ0hBJ0k > div, ._35oEP5zLnhKEbj5BlkTBUA, ._1ti9kvv_PMZEF2phzAjsGW > div, ._28TEYBuEdOuE3kN6UyoKMa div, ._3Oa0THmZ3f5iZXAQ0hBJ0k.WjuR4W-BBrvdtABBeKUMx div, ._3m20hIKOhTTeMgPnfMbVNN,
- /* --------- 9gag */ .post-container .post-view > picture,
- /* ------- feedly */ .PinableImageContainer, .entryBody,
- /* -------- 4chan */ div.post div.file a,
- /* --- deviantart */ ._3_LJY, ._2e1g3, ._2SlAD, ._1R2x6
- `;
- // target img
- const imgElements = `
- /* ------- reddit */ ._2_tDEnGMLxpM6uOa2kaDB3, ._1dwExqTGJH2jnA-MYGkEL-, ._2_tDEnGMLxpM6uOa2kaDB3._1XWObl-3b9tPy64oaG6fax,
- /* --------- 9gag */ .post-container .post-view > picture > img,
- /* ------- feedly */ .pinable, .entryBody img,
- /* -------- 4chan */ div.post div.file img:nth-child(1), ._3Oa0THmZ3f5iZXAQ0hBJ0k.WjuR4W-BBrvdtABBeKUMx img, div.post div.file .fileThumb img,
- /* --- deviantart */ ._3_LJY img, ._2e1g3 img, ._2SlAD img, ._1R2x6 img
- `;
- // excluded element
- const nopeElements = `
- /* ------- reddit */ ._2ED-O3JtIcOqp8iIL1G5cg
- `;
- // specialElements were if targeted, will call it's paired function
- const specialElements = [
- /* -------- 4chan */ { selector: 'div.post div.file .fileThumb img', func: SP1 }
- ];
- function SP1(imageElement) {
- let src = imageElement.getAttribute('src');
- if (src && src.includes('s.jpg')) {
- let newSrc = src.replace('s.jpg', '.jpg');
- imageElement.setAttribute('src', newSrc);
- }
- }
- //-------------------------------------------------------------------------
- // Variables
- const currentHref = window.location.href;
- let enableP, positionP, intervalP, URLmatched;
- Object.keys(siteConfig).some((config) => {
- const regex = new RegExp(config);
- if (currentHref.match(regex)) {
- [enableP, positionP, intervalP] = siteConfig[config];
- URLmatched = true;
- return true;
- }
- });
- // The HoverZoomMinus Function---------------------------------------------
- function HoverZoomMinus() {
- let isshowPopupEnabled = true;
- isshowPopupEnabled = true;
- // Style for the popup image
- const style = document.createElement('style');
- style.type = 'text/css';
- style.innerHTML = `
- .popup-image {
- max-height: calc(90vh - 10px);
- z-index: 1000;
- display: none;
- cursor: move;}`;
- document.head.appendChild(style);
- // Creating the popup image and backdrop
- const popup = document.createElement('img');
- popup.className = 'popup-image';
- document.body.appendChild(popup);
- const backdrop = document.createElement('div');
- backdrop.className = 'popup-backdrop';
- backdrop.style.cssText = `
- position: fixed;
- top: 0;
- left: 0;
- width: 100vw;
- height: 100vh;
- display: none;`;
- document.body.appendChild(backdrop);
- //-------------------------------------------------------------------------
- // Zoom, Pan, Scroll
- let isLocked = false;
- let offsetX, offsetY;
- let scale = 1;
- const ZOOM_SPEED = 0.005;
- let clickTimeout;
- popup.addEventListener('click', function(event) {
- // Clear the timeout if it's set
- if (clickTimeout) clearTimeout(clickTimeout);
- // Set a timeout to execute the single click logic
- clickTimeout = setTimeout(function() {
- isLocked = !isLocked;
- if (isLocked) {
- popup.style.borderLeft = '3px solid #00ff00';
- popup.style.borderRight = '3px solid #00ff00';
- let rect = popup.getBoundingClientRect();
- offsetX = event.clientX - rect.left - (rect.width / 2);
- offsetY = event.clientY - rect.top - (rect.height / 2);
- } else {
- popup.style.borderLeft = '';
- popup.style.borderRight = '';
- }
- }, 300); // Delay for the single click logic
- });
- document.addEventListener('mousemove', function(event) {
- if (isLocked) {
- popup.style.left = (event.clientX - offsetX) + 'px';
- popup.style.top = (event.clientY - offsetY) + 'px';
- }
- });
- function ZoomOrScroll(event) {
- event.preventDefault();
- if (isLocked) {
- let deltaY = event.deltaY * -ZOOM_SPEED;
- let newTop = parseInt(popup.style.top) || 0;
- newTop += deltaY * 100;
- popup.style.top = newTop + 'px';
- offsetY -= deltaY * 100;
- } else {
- scale += event.deltaY * -ZOOM_SPEED;
- scale = Math.min(Math.max(0.125, scale), 10);
- popup.style.transform = `translate(-50%, -50%) scale(${scale})`;
- }
- }
- popup.addEventListener('wheel', ZoomOrScroll);
- //-------------------------------------------------------------------------
- // show popup
- function showPopup(src, mouseX, mouseY) {
- if (!isshowPopupEnabled) return;
- popup.src = src;
- popup.style.display = 'block';
- popup.style.position = 'fixed';
- popup.style.transform = 'translate(-50%, -50%)';
- backdrop.style.display = 'block';
- backdrop.style.zIndex = '999';
- backdrop.style.backdropFilter = 'blur(10px)';
- if (positionP === 'center') {
- popup.style.top = '50%';
- popup.style.left = '50%';
- } else {
- popup.style.top = `${mouseY}px`;
- popup.style.left = `${mouseX}px`;
- }
- }
- let popupTimer;
- document.addEventListener('mouseover', function(e) {
- if (popupTimer) return;
- let target = e.target.closest(imgContainers);
- if (!target) return;
- if (target.querySelector(nopeElements)) return;
- let currentContainer = target;
- const imageElement = currentContainer.querySelector(imgElements);
- specialElements.forEach(pair => {
- if (imageElement.matches(pair.selector)) {
- pair.func(imageElement);
- }
- });
- if (imageElement) {
- if (intervalP === '') {
- if (positionP === 'center') {
- showPopup(imageElement.src);
- } else {
- showPopup(imageElement.src, e.clientX, e.clientY);
- }
- } else {
- popupTimer = setTimeout(() => {
- if (positionP === 'center') {
- showPopup(imageElement.src);
- } else {
- showPopup(imageElement.src, e.clientX, e.clientY);
- }
- popupTimer = null;
- }, parseInt(intervalP));
- }
- }
- });
- //-------------------------------------------------------------------------
- // hide popup
- function hidePopup() {
- if (!ishidePopupEnabled) return;
- isshowPopupEnabled = true;
- if (popupTimer) {
- clearTimeout(popupTimer);
- }
- document.body.appendChild(backdrop);
- popup.style.display = 'none';
- popup.style.left = '50%';
- popup.style.top = '50%';
- popup.style.position = 'fixed';
- popup.style.transform = 'translate(-50%, -50%) scale(1)';
- popup.style.borderLeft = '';
- popup.style.borderRight = '';
- popup.style.outline = '';
- backdrop.style.zIndex = '';
- backdrop.style.display = 'none';
- backdrop.style.backdropFilter = '';
- isLocked = false;
- }
- document.addEventListener('mouseout', function(e) {
- let target = e.target.closest('.imgContainers');
- let relatedTarget = e.relatedTarget;
- if (target && (!relatedTarget || (!relatedTarget.matches('.popup-image') && !relatedTarget.closest('.imgContainers')))) {
- hidePopup();
- if (intervalP !== '') {
- popupTimer = setTimeout(() => {
- popupTimer = null;
- }, parseInt(intervalP));
- }
- }
- });
- popup.addEventListener('mouseout', function() {
- hidePopup();
- if (intervalP !== '') {
- popupTimer = setTimeout(() => {
- popupTimer = null;
- }, parseInt(intervalP));
- }
- });
- document.addEventListener('keydown', function(event) {
- if (event.key === "Escape") {
- event.preventDefault();
- hidePopup();
- }
- });
- //-------------------------------------------------------------------------
- // lock popup in screen
- let ishidePopupEnabled = true;
- function togglehidePopup(event) {
- ishidePopupEnabled = !ishidePopupEnabled;
- popup.style.outline = ishidePopupEnabled ? '' : '3px solid #ae0001';
- }
- popup.addEventListener('dblclick', function(event) {
- clearTimeout(clickTimeout);
- togglehidePopup();
- });
- backdrop.addEventListener('dblclick', function(event) {
- clearTimeout(clickTimeout);
- ishidePopupEnabled = true;
- hidePopup();
- });
- backdrop.addEventListener('click', function(event) {
- if (clickTimeout) clearTimeout(clickTimeout);
- clickTimeout = setTimeout(function() {
- backdrop.style.zIndex = '';
- backdrop.style.display = 'none';
- backdrop.style.backdropFilter = '';
- isshowPopupEnabled = false;
- }, 300);
- });
- }
- //-------------------------------------------------------------------------
- // Is to be run -----------------------------------------------------------
- if (URLmatched) {
- const indicatorBar = document.createElement('div');
- indicatorBar.style.cssText = `
- position: fixed;
- bottom: 0;
- left: 50%;
- transform: translateX(-50%);
- z-index: 9999;
- height: 30px;
- width: 50vw;
- background: #0000;`;
- document.body.appendChild(indicatorBar);
- function toggleIndicator() {
- enableP = 1 - enableP;
- indicatorBar.style.background = enableP ? 'linear-gradient(to right, rgba(50, 190, 152, 0) 0%, rgba(50, 190, 152, 0.5) 25%, rgba(50, 190, 152, 0.5) 75%, rgba(50, 190, 152, 0) 100%)' : 'linear-gradient(to right, rgba(174, 0, 1, 0) 0%, rgba(174, 0, 1, 0.5) 25%, rgba(174, 0, 1, 0.5) 75%, rgba(174, 0, 1, 0) 100%)';
- setTimeout(() => {
- indicatorBar.style.background = '#0000';
- }, 1000);
- if (enableP === 1) {
- HoverZoomMinus();
- } else {
- const existingPopup = document.body.querySelector('.popup-image');
- if (existingPopup) document.body.removeChild(existingPopup);
- const existingBackdrop = document.body.querySelector('.popup-backdrop');
- if (existingBackdrop) document.body.removeChild(existingBackdrop);
- }
- }
- let hoverTimeout;
- indicatorBar.addEventListener('mouseenter', () => {
- hoverTimeout = setTimeout(toggleIndicator, 500);
- });
- indicatorBar.addEventListener('mouseleave', () => {
- clearTimeout(hoverTimeout);
- indicatorBar.style.background = '#0000';
- });
- if (enableP === 1) {
- HoverZoomMinus();
- }
- } else {
- return;
- }
- })();