您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
image popup: zoom, pan, scroll, pin, scale
当前为
- // ==UserScript==
- // @name Hover Zoom Minus --
- // @namespace Hover Zoom Minus --
- // @version 1.0.7
- // @description image popup: zoom, pan, scroll, pin, scale
- // @author Ein, Copilot AI
- // @match *://*/*
- // @license MIT
- // @grant none
- // ==/UserScript==
- // 01. to use hover over the image(container) to view a popup of the target image
- // 02. to zoom in/out use wheel up/down.
- // 03. click left mouse to lock popup this will make it move along with the mouse, click again to release (indicated by green border)
- // 04. while being locked"Y" the wheel up/down will act as scroll up/down
- // 05. double click will lock it on screen preventing it from being hidden
- // 06. hover below the image and click blue bar this will make a 3rd mode for wheel bottom, which will scroll next/previous image under an album
- // 07. 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
- // 08. double clicking on blurred background will de-spawn popup
- // 09. click on the corner to toggle scaling (blue) will retain current aspect ratio, double clicking will turn to 2nd mode for scaling (magenta) will not retain current aspect ratio
- // 10. return to original aspect ration via clicking on sides, if it's in an album to reset to aspect ratio on bottom side use double click
- // 11. 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'],
- 'home': [1, 'center', '0'] /* for testing */
- };
- // image container [hover box where popup triggers]
- const imgContainers = `
- /* ------- reddit */ ._3BxRNDoASi9FbGX01ewiLg, ._3Oa0THmZ3f5iZXAQ0hBJ0k > div, ._35oEP5zLnhKEbj5BlkTBUA, ._1ti9kvv_PMZEF2phzAjsGW > div,
- /* ------- reddit */ ._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
- `;
- // AlbumSelector take note that it will only load image that are already in the DOM tree
- // example reddit will not include all until you press navigator buttons so most of the time this will only load a few image
- // unless you update it via interacting with navigator button thus updating the DOM tree
- let albumSelector = [
- /* ---reddit */ { imgElement: '._1dwExqTGJH2jnA-MYGkEL-', albumElements: '._1apobczT0TzIKMWpza0OhL' },
- /* ---feedly */ { imgElement: '.entryBody > div > img', albumElements: '.entryBody > div' },
- /* ---feedly */ { imgElement: 'div[id^="Article-"] > div > span > img', albumElements: 'div[id^="Article-"]' },
- ];
- // specialElements were if targeted, will call it's paired function
- // for convenience an element className "specialElement" will be remove during mouseout or function hidepopup() is called you can use that with specialElements function for temporary elements
- const specialElements = [
- /* --- 4chan */ { selector: 'div.post div.file .fileThumb img', func: SP1 },
- /* -- reddit */ { selector: '._1dwExqTGJH2jnA-MYGkEL-', func: SP2 }
- ];
- // special function triggered when clicking LeftBar/ wheel down in album mode
- const specialLeftBar = [
- /* -- reddit */ { selector: '._1dwExqTGJH2jnA-MYGkEL-', func: SPL }
- ];
- // special function triggered when clicking RightBar/ wheel up in album mode
- const specialRightBar = [
- /* -- reddit */ { selector: '._1dwExqTGJH2jnA-MYGkEL-', func: SPR }
- ];
- //-------------------------------------------------------------------------
- // Special Funtions -------------------------------------------------------
- // 4chan: replaces thumbnail so popup will use the larger version, or if its animated replace it with that
- function SP1(imageElement) {
- const parentElement = imageElement.parentElement;
- if (parentElement.tagName === 'A') {
- const href = parentElement.getAttribute('href');
- if (href.endsWith('.webm')) {
- const videoElement = document.createElement('video');
- videoElement.src = href;
- videoElement.controls = true;
- parentElement.replaceChild(videoElement, imageElement);
- } else if (href.endsWith('.gif')) {
- imageElement.setAttribute('src', href);
- }
- } else {
- let src = imageElement.getAttribute('src');
- if (src && src.includes('s.jpg')) {
- let newSrc = src.replace('s.jpg', '.jpg');
- imageElement.setAttribute('src', newSrc);
- }
- }
- }
- // reddit: added the label/description of image along with the popup
- // only shows what is currently loaded on DOM tree so when you navigate thru albums in popup it will not automatically update the current label/desc
- function SP2(imageElement) {
- if (enableP === 0) {
- return;
- }
- let closestElement = imageElement.closest('.m3aNC6yp8RrNM_-a0rrfa, .kcerW9lbT-se3SXd-wp2i');
- if (!closestElement) {
- return;
- }
- let descendantElement = closestElement.querySelector('._15nNdGlBIgryHV04IfAfpA');
- if (descendantElement) {
- document.querySelectorAll('.specialElement').forEach(e => e.remove());
- let title = descendantElement.getAttribute('title');
- const specialContent = document.createElement('div');
- specialContent.className = 'specialElement';
- specialContent.style.cssText = 'position:fixed; bottom:80px; left:50%; transform:translateX(-50%); width:100vw; text-align:center; font-size:40px; color:white; text-shadow:0 0 10px rgba(255,255,255,0.7); z-index:99999;';
- specialContent.textContent = title;
- document.body.appendChild(specialContent);
- var specialBackdrop = document.createElement('div');
- specialBackdrop.className = 'specialElement';
- specialBackdrop.style.cssText = 'position:fixed; bottom:60px; left:0; width:100vw; height:80px; background:rgba(0,0,0,0.2); backdrop-filter:blur(5px); z-index:99998;';
- document.body.appendChild(specialBackdrop);
- } else {
- return;
- }
- }
- function SPL(imageElement) {
- document.querySelectorAll('.specialElement').forEach(e => e.remove());
- let closestElement = imageElement.closest('.kcerW9lbT-se3SXd-wp2i');
- var element = closestElement.querySelector('._1fSFPkxZ9pToLETLQT2dmc');
- if (element) element.click();
- let descendantElement = closestElement.querySelector('._15nNdGlBIgryHV04IfAfpA');
- if (descendantElement) {
- let title = descendantElement.getAttribute('title');
- const specialContent = document.createElement('div');
- specialContent.className = 'specialElement';
- specialContent.style.cssText = 'position:fixed; bottom:80px; left:50%; transform:translateX(-50%); width:100vw; text-align:center; font-size:40px; color:white; text-shadow:0 0 10px rgba(255,255,255,0.7); z-index:99999;';
- specialContent.textContent = title;
- document.body.appendChild(specialContent);
- var specialBackdrop = document.createElement('div');
- specialBackdrop.className = 'specialElement';
- specialBackdrop.style.cssText = 'position:fixed; bottom:60px; left:0; width:100vw; height:80px; background:rgba(0,0,0,0.2); backdrop-filter:blur(5px); z-index:99998;';
- document.body.appendChild(specialBackdrop);
- } else {
- return;
- }
- }
- function SPR(imageElement) {
- document.querySelectorAll('.specialElement').forEach(e => e.remove());
- let closestElement = imageElement.closest('.kcerW9lbT-se3SXd-wp2i');
- var element = closestElement.querySelector('._3-JCOd-nY76g29C7ZVX_kl:last-child');
- if (element) element.click();
- let descendantElement = closestElement.querySelector('._15nNdGlBIgryHV04IfAfpA');
- if (descendantElement) {
- let title = descendantElement.getAttribute('title');
- const specialContent = document.createElement('div');
- specialContent.className = 'specialElement';
- specialContent.style.cssText = 'position:fixed; bottom:80px; left:50%; transform:translateX(-50%); width:100vw; text-align:center; font-size:40px; color:white; text-shadow:0 0 10px rgba(255,255,255,0.7); z-index:99999;';
- specialContent.textContent = title;
- document.body.appendChild(specialContent);
- var specialBackdrop = document.createElement('div');
- specialBackdrop.className = 'specialElement';
- specialBackdrop.style.cssText = 'position:fixed; bottom:60px; left:0; width:100vw; height:80px; background:rgba(0,0,0,0.2); backdrop-filter:blur(5px); z-index:99998;';
- document.body.appendChild(specialBackdrop);
- } else {
- return;
- }
- }
- //-------------------------------------------------------------------------
- // Configuration 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;
- const style = document.createElement('style');
- style.type = 'text/css';
- style.innerHTML = `
- .popup-container {
- display: none;
- z-index: 1001;
- cursor: move;
- }
- .popup-image {
- max-height: calc(90vh - 10px);
- display: none;
- }
- .popup-backdrop {
- position: fixed;
- top: 0;
- left: 0;
- width: 100vw;
- height: 100vh;
- display: none;
- z-index: 1000;
- }
- .centerBox {
- top: 40px;
- left: 40px;
- position: absolute;
- height: calc(100% - 80px);
- width: calc(100% - 80px);
- }
- .TopBar,
- .BottomBar,
- .LeftBar,
- .RightBar {
- opacity: 0;
- box-sizing: border-box;
- background: #0000;
- position: absolute;
- z-index: 9999;
- &::after {
- content: "";
- position: absolute;
- }
- }
- .TopBar,
- .BottomBar {
- height: 40px;
- width: calc(100% - 80px);
- left: 40px;
- &::after {
- display: none;
- width: 25px;
- height: 25px;
- transform: rotate(45deg) translateX(-50%) translateY(-50%);
- }
- }
- .TopBar { top: 0; }
- .BottomBar { bottom: 0; }
- .TopBar::after {
- left: calc(50% - 17px);
- top: calc(50% + 15px);
- border-top: 5px solid #6f8e9e;
- border-left: 5px solid #6f8e9e;
- }
- .BottomBar::after {
- left: calc(50% - 2px);
- bottom: -8px;
- border-bottom: 5px solid #6f8e9e;
- border-right: 5px solid #6f8e9e;
- }
- .LeftBar,
- .RightBar {
- height: calc(100% - 80px);
- width: 40px;
- top: 40px;
- &::before {
- content: "";
- display: block;
- position: absolute;
- top: 50%;
- width: 40px;
- height: 40px;
- transform: translateY(-50%);
- border-radius: 9999px;
- background: #242526;
- }
- &::after {
- content: "";
- display: block;
- position: absolute;
- top: calc(50% + -2px);
- width: 15px;
- height: 15px;
- }
- &:hover::before {
- display: none;
- }
- &:hover::after {
- width: 25px;
- height: 25px;
- border-color: #6f8e9e;
- border-width: 5px;
- }
- }
- .LeftBar { left: 0; }
- .RightBar { right: 0; }
- .LeftBar::before { left: 5px; }
- .RightBar::before { right: 5px; }
- .LeftBar:hover::after { left: 3px; }
- .RightBar:hover::after { right: 3px; }
- .LeftBar::after {
- transform: rotate(45deg) translateY(-50%);
- border-bottom: 3px solid #777;
- border-left: 3px solid #777;
- left: 12px;
- }
- .RightBar::after {
- transform: rotate(-45deg) translateY(-50%);
- border-bottom: 3px solid #777;
- border-right: 3px solid #777;
- right: 12px;
- }
- .CornerBox {
- box-sizing: border-box;
- height: 40px;
- width: 40px;
- background: #0000;
- position: absolute;
- z-index: 9999;
- }
- .CornerBox.TR {
- top: 0;
- right: 0;
- text-align: center;
- line-height: 25px;
- color:white;
- text-shadow:0 0 10px rgba(255,255,255,0.7);
- }
- .CornerBox.TL {
- top: 0;
- left: 0;
- }
- .CornerBox.BR {
- bottom: 0;
- right: 0;text-align: center;
- line-height: 25px;
- color:white;
- text-shadow:0 0 10px rgba(255,255,255,0.7);
- }
- .CornerBox.BL {
- bottom: 0;
- left: 0;
- }
- `;
- document.head.appendChild(style);
- const backdrop = document.createElement('div');
- backdrop.className = 'popup-backdrop';
- document.body.appendChild(backdrop);
- const popupContainer = document.createElement('div');
- popupContainer.className = 'popup-container';
- document.body.appendChild(popupContainer);
- const popup = document.createElement('img');
- popup.className = 'popup-image';
- popupContainer.appendChild(popup);
- const BottomBar = document.createElement('div');
- BottomBar.className = 'BottomBar';
- popupContainer.appendChild(BottomBar);
- const TopBar = document.createElement('div');
- TopBar.className = 'TopBar';
- popupContainer.appendChild(TopBar);
- const RightBar = document.createElement('div');
- RightBar.className = 'RightBar';
- popupContainer.appendChild(RightBar);
- const LeftBar = document.createElement('div');
- LeftBar.className = 'LeftBar';
- popupContainer.appendChild(LeftBar);
- const TR = document.createElement('div');
- TR.className = 'CornerBox TR';
- popupContainer.appendChild(TR);
- const TL = document.createElement('div');
- TL.className = 'CornerBox TL';
- popupContainer.appendChild(TL);
- const BR = document.createElement('div');
- BR.className = 'CornerBox BR';
- popupContainer.appendChild(BR);
- const BL = document.createElement('div');
- BL.className = 'CornerBox BL';
- popupContainer.appendChild(BL);
- const centerBox = document.createElement('div');
- centerBox.className = 'popup centerBox';
- popupContainer.appendChild(centerBox);
- const style2 = document.createElement('style');
- style2.type = 'text/css';
- document.head.appendChild(style2);
- //-------------------------------------------------------------------------
- // Variable
- const ZOOM_SPEED = 0.005;
- let pageDirection;
- let isLockedY = false;
- let isLockedX = false;
- let scale = 1;
- let clickTimeout;
- let popupTimer;
- let isScale, isScaleTR, isScaleBR, isScaleTL, isScaleBL;
- let rect, rectT, rectH, rectL, rectW;
- let rectIH, rectIW, rectIT, rectIL, rectIRatio;
- let rectzT, rectzH, rectzL, rectzW, rectzRatio;
- let scaleCurrentX, scaleCurrentY;
- let scaleFactorX, scaleFactorY;
- let offsetX, offsetY, offsetXR, offsetYT, offsetXL, offsetYB;
- let offsetRatioY, offsetRatioX;
- let ishidePopupEnabled = true;
- let ScaleMode2 = false;
- let imgElementsList = [];
- let currentZeroImgElement;
- let rectIzRatio;
- function NoMode() {
- isLockedY = false;
- isLockedX = false;
- isScale = false;
- isScaleTR = false;
- isScaleTL = false;
- isScaleBL = false;
- isScaleBR = false;
- popupContainer.style.border = '';
- TR.style.border = '';
- BR.style.border = '';
- TL.style.border = '';
- BL.style.border = '';
- }
- function LockedYMode() {
- NoMode();
- isLockedY = true;
- popupContainer.style.borderLeft = '6px solid #00ff00';
- popupContainer.style.borderRight = '6px solid #00ff00';
- LeftBar.style.opacity = '0';
- RightBar.style.opacity = '0';
- }
- function LockedXMode() {
- NoMode();
- LockedScreen();
- isLockedX = true;
- popupContainer.style.borderTop = '6px solid #00ff00';
- popupContainer.style.borderBottom = '6px solid #00ff00';
- LeftBar.style.opacity = '1';
- RightBar.style.opacity = '1';
- style2.innerHTML = `
- .LeftBar::before,
- .LeftBar::after,
- .RightBar::before,
- .RightBar::after {
- display: block;
- }
- `;
- }
- function toggleLockedScreen(event) {
- ishidePopupEnabled = !ishidePopupEnabled;
- popupContainer.style.outline = ishidePopupEnabled ? '' : '6px solid #ae0001';
- }
- function LockedScreen() {
- ishidePopupEnabled = false;
- popupContainer.style.outline = '6px solid #ae0001';
- }
- function ScalingMode1() {
- TL.style.borderTop = '6px solid #0000ff';
- TR.style.borderTop = '6px solid #0000ff';
- TL.style.borderLeft = '6px solid #0000ff';
- BL.style.borderLeft = '6px solid #0000ff';
- TR.style.borderRight = '6px solid #0000ff';
- BR.style.borderRight = '6px solid #0000ff';
- BR.style.borderBottom = '6px solid #0000ff';
- BL.style.borderBottom = '6px solid #0000ff';
- }
- function ScalingMode2() {
- ScalingMode1();
- TL.style.borderColor = '#ff00ff';
- TR.style.borderColor = '#ff00ff';
- BL.style.borderColor = '#ff00ff';
- BR.style.borderColor = '#ff00ff';
- }
- function ScalingMode0() {
- TL.style.border = '';
- TR.style.border = '';
- BL.style.border = '';
- BR.style.border = '';
- }
- function ResetGeometry() {
- let rectF = popup.getBoundingClientRect();
- rectzH = rectF.height;
- rectzW = rectF.width;
- rectzT = rectF.top;
- rectzL = rectF.left;
- popup.style.maxHeight = rectzH + 'px';
- popup.style.height = rectzH + 'px';
- popup.style.width = rectzW + 'px';
- popupContainer.style.top = rectzT + (rectzH / 2) + 'px';
- popupContainer.style.left = rectzL + (rectzW / 2) + 'px';
- popupContainer.style.transformOrigin = '50% 50% 0px';
- popupContainer.style.transform = `translate(-50%, -50%) scaleX(1) scaleY(1)`;
- }
- function BarClear() {
- TL.style.border = '';
- TR.style.border = '';
- BL.style.border = '';
- BR.style.border = '';
- TL.style.background = '';
- TR.style.background = '';
- BL.style.background = '';
- BR.style.background = '';
- TopBar.style.background = '';
- LeftBar.style.background = '';
- RightBar.style.background = '';
- BottomBar.style.background = '';
- popupContainer.style.border = '';
- LeftBar.style.opacity = '0';
- RightBar.style.opacity = '0';
- }
- function NavigateAlbum() {
- let pair = albumSelector.find(pair => currentZeroImgElement.matches(pair.imgElement));
- if (pair) {
- let ancestorElement = currentZeroImgElement.closest(pair.albumElements);
- if (ancestorElement) {
- imgElementsList = Array.from(ancestorElement.querySelectorAll(pair.imgElement));
- let zeroIndex = imgElementsList.indexOf(currentZeroImgElement);
- let direction = pageDirection;
- let newIndex = zeroIndex + direction;
- TR.textContent = `${newIndex + 1}/${imgElementsList.length}`;
- if (newIndex <= 0) {
- LeftBar.style.display = 'none';
- TR.textContent = `1/${imgElementsList.length}`;
- } else {
- LeftBar.style.display = '';
- }
- if (newIndex >= imgElementsList.length - 1) {
- RightBar.style.display = 'none';
- TR.textContent = `${imgElementsList.length}/${imgElementsList.length}`;
- } else {
- RightBar.style.display = '';
- }
- if (newIndex < 0 || newIndex >= imgElementsList.length) {
- return;
- }
- currentZeroImgElement = imgElementsList[newIndex];
- popup.src = currentZeroImgElement.src;
- }
- }
- }
- // Mouse Click: Center
- centerBox.addEventListener('click', function(event) {
- if (clickTimeout) clearTimeout(clickTimeout);
- clickTimeout = setTimeout(function() {
- ResetGeometry();
- if (!isScale) {
- isLockedY = !isLockedY;
- }
- if (isLockedY) {
- LockedYMode();
- let rect = popupContainer.getBoundingClientRect();
- offsetX = event.clientX - rect.left - (rect.width / 2);
- offsetY = event.clientY - rect.top - (rect.height / 2);
- } else {
- NoMode();
- }
- }, 300);
- });
- centerBox.addEventListener('dblclick', function(event) {
- clearTimeout(clickTimeout);
- toggleLockedScreen();
- if (!ishidePopupEnabled) {
- backdrop.style.display = 'block';
- backdrop.style.zIndex = '999';
- backdrop.style.backdropFilter = 'blur(10px)';
- }
- });
- //-------------------------------------------------------------------------
- // Mouse Click: Corners
- document.querySelectorAll('.CornerBox').forEach(element => {
- element.addEventListener('click', function(event) {
- ishidePopupEnabled = false;
- if (isScale) {
- BarClear();
- isLockedY = false;
- isLockedX = false;
- popup.style.border = '';
- const clickedElement = event.target;
- const popupContainer = clickedElement.parentElement;
- const currentTransform = window.getComputedStyle(popupContainer).transform;
- const matrixMatch = currentTransform.match(/^matrix\(([^,]+), [^,]+, [^,]+, ([^,]+), [^,]+, [^,]+\)$/);
- if (matrixMatch) {
- scaleCurrentX = parseFloat(matrixMatch[1]);
- scaleCurrentY = parseFloat(matrixMatch[2]);
- }
- let rect = popupContainer.getBoundingClientRect();
- offsetYT = event.clientY - rect.top;
- offsetXL = event.clientX - rect.left;
- offsetYB = rect.height + rect.top - event.clientY;
- offsetXR = rect.width + rect.left - event.clientX;
- rectT = rect.top;
- rectL = rect.left;
- rectH = rect.height;
- rectW = rect.width;
- } else {
- LockedScreen();
- ResetGeometry();
- }
- });
- });
- document.querySelectorAll('.CornerBox').forEach(element => {
- element.addEventListener('click', function(event) {
- if (clickTimeout) clearTimeout(clickTimeout);
- isScale = !isScale;
- }, 300);
- });
- document.querySelectorAll('.CornerBox').forEach(element => {
- element.addEventListener('dblclick', function(event) {
- clearTimeout(clickTimeout);
- ScaleMode2 = !ScaleMode2;
- });
- });
- TL.addEventListener('click', function(event) {
- if (clickTimeout) clearTimeout(clickTimeout);
- clickTimeout = setTimeout(function() {
- isScaleTL = !isScaleTL;
- isScaleTR = false;
- isScaleBL = false;
- isScaleBR = false;
- }, 300);
- });
- TR.addEventListener('click', function(event) {
- if (clickTimeout) clearTimeout(clickTimeout);
- clickTimeout = setTimeout(function() {
- isScaleTL = false;
- isScaleTR = !isScaleTR;
- isScaleBL = false;
- isScaleBR = false;
- }, 300);
- });
- BL.addEventListener('click', function(event) {
- if (clickTimeout) clearTimeout(clickTimeout);
- clickTimeout = setTimeout(function() {
- isScaleTL = false;
- isScaleTR = false;
- isScaleBL = !isScaleBL;
- isScaleBR = false;
- }, 300);
- });
- BR.addEventListener('click', function(event) {
- if (clickTimeout) clearTimeout(clickTimeout);
- clickTimeout = setTimeout(function() {
- isScaleTL = false;
- isScaleTR = false;
- isScaleBL = false;
- isScaleBR = !isScaleBR;
- }, 300);
- });
- //-------------------------------------------------------------------------
- // Mouse Move: Pan, Scale
- document.addEventListener('mousemove', function(event) {
- // Panning mode: popup locked and follows the mouse
- if (isLockedY) {
- popupContainer.style.left = (event.clientX - offsetX) + 'px';
- popupContainer.style.top = (event.clientY - offsetY) + 'px';
- } else if (isScale) {
- ScalingMode1();
- if (ScaleMode2) {
- ScalingMode2();
- }
- if (isScaleTL) {
- popupContainer.style.transformOrigin = '100% 100% 0px';
- scaleFactorY = scaleCurrentY * (1 + (rectT - event.clientY + offsetYT) / rectH);
- scaleFactorX = scaleCurrentX * (1 + (rectL - event.clientX + offsetXL) / rectW);
- } else if (isScaleTR) {
- popupContainer.style.transformOrigin = '0 100% 0px';
- scaleFactorY = scaleCurrentY * (1 + (rectT - event.clientY + offsetYT) / rectH);
- scaleFactorX = scaleCurrentX * ((event.clientX - rectL + offsetXR) / rectW);
- } else if (isScaleBL) {
- popupContainer.style.transformOrigin = '100% 0% 0px';
- scaleFactorY = scaleCurrentY * ((event.clientY - rectT + offsetYB) / rectH);
- scaleFactorX = scaleCurrentX * (1 + (rectL - event.clientX + offsetXL) / rectW);
- } else if (isScaleBR) {
- popupContainer.style.transformOrigin = '0% 0% 0px';
- scaleFactorY = scaleCurrentY * ((event.clientY - rectT + offsetYB) / rectH);
- scaleFactorX = scaleCurrentX * ((event.clientX - rectL + offsetXR) / rectW);
- }
- if (ScaleMode2) {
- popupContainer.style.transform = `translate(-50%, -50%) scaleX(${scaleFactorX}) scaleY(${scaleFactorY})`;
- } else {
- popupContainer.style.transform = `translate(-50%, -50%) scaleX(${scaleFactorX}) scaleY(${scaleFactorX})`;
- }
- }
- });
- // Mouse Wheel: Zoom, Scroll, Navigate
- function ZoomOrScroll(event) {
- event.preventDefault();
- if (isLockedY) {
- let deltaY = event.deltaY * -ZOOM_SPEED;
- let newTop = parseInt(popupContainer.style.top) || 0;
- newTop += deltaY * 100;
- popupContainer.style.top = newTop + 'px';
- offsetY -= deltaY * 100;
- } else if (isLockedX && currentZeroImgElement) {
- pageDirection = event.deltaY > 0 ? 1 : -1;
- NavigateAlbum();
- if (pageDirection === 1) {
- const imageElement = currentContainer.querySelector(imgElements);
- specialRightBar.forEach(pair => {
- if (imageElement.matches(pair.selector)) {
- pair.func(imageElement);
- }
- });
- } else {
- const imageElement = currentContainer.querySelector(imgElements);
- specialLeftBar.forEach(pair => {
- if (imageElement.matches(pair.selector)) {
- pair.func(imageElement);
- }
- });
- }
- } else {
- scale += event.deltaY * -ZOOM_SPEED;
- scale = Math.min(Math.max(0.125, scale), 10);
- popupContainer.style.transform = `translate(-50%, -50%) scaleX(${scale}) scaleY(${scale})`;
- }
- }
- popupContainer.addEventListener('wheel', ZoomOrScroll);
- //-------------------------------------------------------------------------
- // Bottom Bar: Album
- BottomBar.addEventListener('mouseenter', function(e) {
- if (isScale) {
- return;
- } else {
- BottomBar.style.opacity = '1';
- let rect = popup.getBoundingClientRect();
- rectzRatio = rect.height / rect.width;
- rectIzRatio = Number(rectIRatio.toFixed(3)) / Number(rectzRatio.toFixed(3));
- if (isAlbum) {
- if (!isScale) {
- BottomBar.style.background = 'linear-gradient(to right, rgba(0, 0, 255, 0) 0%, rgba(0, 0, 255, 0.5) 25%, rgba(0, 0, 255, 0.5) 75%, rgba(0, 0, 255, 0) 100%)';
- }
- } else {
- BottomBar.style.background = '';
- if (!( (rectIzRatio === 1) || isScale ) ) {
- style2.innerHTML = `
- .BottomBar::after {
- display: block;
- }
- `;
- BL.style.background = 'rgba(0, 0, 0, 0.5)';
- BR.style.background = 'rgba(0, 0, 0, 0.5)';
- BottomBar.style.background = 'rgba(0, 0, 0, 0.5)';
- } else {
- style2.innerHTML = `
- .BottomBar::after {
- display: none;
- }
- `;
- }
- }
- }
- });
- BottomBar.addEventListener('mouseleave', function() {
- BottomBar.style.opacity = '0';
- if (!isLockedX) {
- BarClear();
- }
- });
- BottomBar.addEventListener('click', function(event) {
- if (clickTimeout) clearTimeout(clickTimeout);
- clickTimeout = setTimeout(function() {
- if (!isScale) {
- LeftBar.style.opacity = '0';
- RightBar.style.opacity = '0';
- }
- if (isAlbum) {
- ResetGeometry();
- isLockedX = !isLockedX;
- if (isLockedX) {
- LockedXMode();
- LeftBar.style.opacity = '1';
- RightBar.style.opacity = '1';
- } else {
- popupContainer.style.border = '';
- }
- } else {
- ResetGeometry();
- if (isScale) {
- isScale = false;
- popup.style.maxHeight = rectzH + 'px';
- popup.style.height = rectzH + 'px';
- offsetRatioY = 0;
- } else {
- popup.style.maxHeight = 'unset';
- popup.style.height = '';
- offsetRatioY = (rectzH - rectzW * rectIRatio) / 2 ;
- }
- popupContainer.style.top = rectzT + (rectzH / 2) + offsetRatioY + 'px';
- }
- }, 300);
- });
- BottomBar.addEventListener('dblclick', function(event) {
- clearTimeout(clickTimeout);
- if (isAlbum) {
- ResetGeometry();
- if (isScale) {
- popup.style.maxHeight = rectzH + 'px';
- popup.style.height = rectzH + 'px';
- offsetRatioY = 0;
- } else {
- popup.style.maxHeight = 'unset';
- popup.style.height = '';
- offsetRatioY = (rectzH - rectzW * rectIRatio) / 2 ;
- }
- popupContainer.style.top = rectzT + (rectzH / 2) + offsetRatioY + 'px';
- BarClear();
- } else {
- return;
- }
- });
- //-------------------------------------------------------------------------
- // Indicators
- document.querySelectorAll('.CornerBox').forEach(element => {
- element.addEventListener('mouseenter', function(event) {
- ScalingMode1();
- if (ScaleMode2) {
- ScalingMode2();
- }
- });
- element.addEventListener('mouseleave', function(event) {
- if (!isScale) {
- ScalingMode0();
- }
- });
- });
- // Re-scale/ Navigate
- TopBar.addEventListener('click', function(event) {
- if (clickTimeout) clearTimeout(clickTimeout);
- clickTimeout = setTimeout(function() {
- ResetGeometry();
- if (isScale) {
- isScale = false;
- popup.style.maxHeight = rectzH + 'px';
- popup.style.height = rectzH + 'px';
- offsetRatioY = 0;
- } else {
- popup.style.maxHeight = 'unset';
- popup.style.height = '';
- offsetRatioY = (rectzH - rectzW * rectIRatio) / 2 ;
- }
- popupContainer.style.top = rectzT + (rectzH / 2) - offsetRatioY + 'px';
- BarClear();
- }, 300);
- });
- TopBar.addEventListener('dblclick', function(event) {
- clearTimeout(clickTimeout);
- LockedScreen();
- });
- let zeroIndex;
- LeftBar.addEventListener('click', function(event) {
- if (clickTimeout) clearTimeout(clickTimeout);
- clickTimeout = setTimeout(function() {
- ResetGeometry();
- if (isScale) {
- isScale = false;
- popup.style.width = rectzW + 'px';
- offsetRatioX = 0;
- } else {
- popup.style.width = '';
- offsetRatioX = (rectzW - (rectzH / rectIRatio)) / 2 ;
- }
- if (isLockedX && currentZeroImgElement) {
- pageDirection = -1;
- NavigateAlbum();
- TL.style.background = 'rgba(0, 0, 0, 0.5)';
- BL.style.background = 'rgba(0, 0, 0, 0.5)';
- LeftBar.style.background = 'rgba(0, 0, 0, 0.5)';
- const imageElement = currentContainer.querySelector(imgElements);
- specialLeftBar.forEach(pair => {
- if (imageElement.matches(pair.selector)) {
- pair.func(imageElement);
- }
- });
- } else {
- popupContainer.style.left = rectzL + (rectzW / 2) - offsetRatioX + 'px';
- }
- }, 300);
- });
- RightBar.addEventListener('click', function(event) {
- if (clickTimeout) clearTimeout(clickTimeout);
- clickTimeout = setTimeout(function() {
- ResetGeometry();
- if (isScale) {
- isScale = false;
- popup.style.width = rectzW + 'px';
- offsetRatioX = 0;
- } else {
- popup.style.width = '';
- offsetRatioX = (rectzW - (rectzH / rectIRatio)) / 2 ;
- }
- if (isLockedX && currentZeroImgElement) {
- pageDirection = 1;
- NavigateAlbum();
- TR.style.background = 'rgba(0, 0, 0, 0.5)';
- BR.style.background = 'rgba(0, 0, 0, 0.5)';
- RightBar.style.background = 'rgba(0, 0, 0, 0.5)';
- const imageElement = currentContainer.querySelector(imgElements);
- specialRightBar.forEach(pair => {
- if (imageElement.matches(pair.selector)) {
- pair.func(imageElement);
- }
- });
- } else {
- popupContainer.style.left = rectzL + (rectzW / 2) + offsetRatioX + 'px';
- }
- }, 300);
- });
- TopBar.addEventListener('mouseenter', function() {
- let rect = popup.getBoundingClientRect();
- rectzRatio = rect.height / rect.width;
- rectIzRatio = Number(rectIRatio.toFixed(3)) / Number(rectzRatio.toFixed(3));
- if (!( (rectIzRatio === 1) || isScale ) ) {
- TopBar.style.opacity = '1';
- style2.innerHTML = `
- .TopBar::after {
- display: block;
- }`;
- TL.style.background = 'rgba(0, 0, 0, 0.5)';
- TR.style.background = 'rgba(0, 0, 0, 0.5)';
- TopBar.style.background = 'rgba(0, 0, 0, 0.5)';
- } else {
- style2.innerHTML = `
- .TopBar::after {
- display: none;
- }`;
- if (ishidePopupEnabled) {
- TopBar.style.opacity = '1';
- TL.style.background = 'rgba(0, 0, 0, 0.5)';
- TR.style.background = 'rgba(0, 0, 0, 0.5)';
- TopBar.style.background = 'rgba(0, 0, 0, 0.5)';
- }
- }
- });
- LeftBar.addEventListener('mouseenter', function() {
- LeftBar.style.opacity = '1';
- let rect = popup.getBoundingClientRect();
- rectzRatio = rect.height / rect.width;
- rectIzRatio = Number(rectIRatio.toFixed(3)) / Number(rectzRatio.toFixed(3));
- if ( isLockedX || !( (rectIzRatio === 1) || isScale ) ) {
- style2.innerHTML = `
- .LeftBar::before, .LeftBar::after {
- display: block;
- }`;
- TL.style.background = 'rgba(0, 0, 0, 0.5)';
- BL.style.background = 'rgba(0, 0, 0, 0.5)';
- LeftBar.style.background = 'rgba(0, 0, 0, 0.5)';
- } else {
- style2.innerHTML = `
- .LeftBar::before, .LeftBar::after {
- display: none;
- }`;
- }
- });
- RightBar.addEventListener('mouseenter', function() {
- RightBar.style.opacity = '1';
- let rect = popup.getBoundingClientRect();
- rectzRatio = rect.height / rect.width;
- rectIzRatio = Number(rectIRatio.toFixed(3)) / Number(rectzRatio.toFixed(3));
- if ( isLockedX || !( (rectIzRatio === 1) || isScale ) ) {
- style2.innerHTML = `
- .RightBar::before, .RightBar::after {
- display: block;
- }`;
- TR.style.background = 'rgba(0, 0, 0, 0.5)';
- BR.style.background = 'rgba(0, 0, 0, 0.5)';
- RightBar.style.background = 'rgba(0, 0, 0, 0.5)';
- } else {
- style2.innerHTML = `
- .RightBar::before, .RightBar::after {
- display: none;
- }`;
- }
- });
- TopBar.addEventListener('mouseleave', function() {
- TopBar.style.opacity = '0';
- TopBar.style.border = '';
- TL.style.background = '';
- TR.style.background = '';
- TopBar.style.background = '';
- if (isScale) {
- TR.style.borderColor = '#0000ff';
- TL.style.borderColor = '#0000ff';
- if (ScaleMode2) {
- TR.style.borderColor = '#ff00ff';
- TL.style.borderColor = '#ff00ff';
- }
- } else {
- TR.style.border = '';
- TL.style.border = '';
- }
- });
- LeftBar.addEventListener('mouseleave', function() {
- if (isLockedX) {
- LeftBar.style.opacity = '1';
- } else {
- LeftBar.style.opacity = '0';
- }
- TL.style.background = '';
- BL.style.background = '';
- LeftBar.style.background = '';
- });
- RightBar.addEventListener('mouseleave', function() {
- if (isLockedX) {
- RightBar.style.opacity = '1';
- } else {
- RightBar.style.opacity = '0';
- }
- TR.style.background = '';
- BR.style.background = '';
- RightBar.style.background = '';
- });
- //-------------------------------------------------------------------------
- // show popup
- function showPopup(src, mouseX, mouseY) {
- if (!isshowPopupEnabled) return;
- ishidePopupEnabled = true;
- if (enableP === 0) return;
- popup.src = src;
- popup.style.display = 'block';
- popupContainer.style.display = 'block';
- popupContainer.style.position = 'fixed';
- popupContainer.style.transform = 'translate(-50%, -50%) scaleX(1) scaleY(1)';
- backdrop.style.display = 'block';
- backdrop.style.zIndex = '999';
- backdrop.style.backdropFilter = 'blur(10px)';
- if (positionP === 'center') {
- popupContainer.style.top = '50%';
- popupContainer.style.left = '50%';
- } else {
- popupContainer.style.top = `${mouseY}px`;
- popupContainer.style.left = `${mouseX}px`;
- }
- let rectI = popup.getBoundingClientRect();
- rectIH = rectI.height;
- rectIW = rectI.width;
- rectIT = rectI.top;
- rectIL = rectI.left;
- rectIRatio = rectIH / rectIW;
- if (isAlbum) {
- LockedXMode();
- }
- }
- let isAlbum;
- let currentContainer;
- document.addEventListener('mouseover', function(e) {
- if (popupTimer) return;
- let target = e.target.closest(imgContainers);
- console.log('Entered imgContainer:', target);
- if (!target) return;
- if (target.querySelector(nopeElements)) return;
- currentContainer = target;
- const imageElement = currentContainer.querySelector(imgElements);
- specialElements.forEach(pair => {
- if (imageElement.matches(pair.selector)) {
- pair.func(imageElement);
- }
- });
- if (imageElement) {
- currentZeroImgElement = imageElement;
- if (currentZeroImgElement) {
- let pair = albumSelector.find(pair => currentZeroImgElement.matches(pair.imgElement));
- if (pair) {
- let closestAlbumElement = currentZeroImgElement.closest(pair.albumElements);
- isAlbum = closestAlbumElement && closestAlbumElement.querySelectorAll(pair.imgElement).length > 1;
- if (isAlbum) {
- imgElementsList = Array.from(closestAlbumElement.querySelectorAll(pair.imgElement));
- let zeroIndex = imgElementsList.indexOf(currentZeroImgElement);
- TR.textContent = `${zeroIndex + 1}/${imgElementsList.length}`;
- if (zeroIndex === 0) {
- LeftBar.style.display = 'none';
- } else {
- LeftBar.style.display = '';
- }
- if (zeroIndex === imgElementsList.length - 1) {
- RightBar.style.display = 'none';
- } else {
- RightBar.style.display = '';
- }
- }
- } else {
- isAlbum = false;
- TR.textContent = '';
- LeftBar.style.display = '';
- RightBar.style.display = '';
- }
- }
- if (intervalP === '') {
- showPopup(imageElement.src, e.clientX, e.clientY);
- } else {
- popupTimer = setTimeout(() => {
- showPopup(imageElement.src, e.clientX, e.clientY);
- popupTimer = null;
- }, parseInt(intervalP));
- }
- }
- });
- //-------------------------------------------------------------------------
- // hide popup
- function hidePopup() {
- if (!ishidePopupEnabled) return;
- imgElementsList = [];
- if (popupTimer) {
- clearTimeout(popupTimer);
- }
- popup.style.display = 'none';
- popupContainer.style.display = 'none';
- NoMode();
- popup.style.maxHeight = 'calc(90vh - 10px)';
- popup.style.width = '';
- popup.style.height = '';
- popupContainer.style.left = '50%';
- popupContainer.style.top = '50%';
- popupContainer.style.position = 'fixed';
- popupContainer.style.transform = 'translate(-50%, -50%) scaleX(1) scaleY(1)';
- popupContainer.style.transformOrigin = '';
- popupContainer.style.outline = '';
- backdrop.style.zIndex = '';
- backdrop.style.display = 'none';
- backdrop.style.backdropFilter = '';
- LeftBar.style.opacity = '0';
- RightBar.style.opacity = '0';
- style2.innerHTML = `
- .LeftBar::before,
- .LeftBar::after,
- .RighttBar::before,
- .RighttBar::after {
- display: none;
- }`;
- document.querySelectorAll('.specialElement').forEach(e => e.remove());
- }
- popupContainer.addEventListener('mouseout', function(event) {
- let relatedTarget = event.relatedTarget;
- if (relatedTarget && (popupContainer.contains(relatedTarget) || relatedTarget.matches('.imgContainers') || relatedTarget.closest('.imgContainers'))) {
- return;
- }
- document.querySelectorAll('.specialElement').forEach(e => e.remove());
- 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
- backdrop.addEventListener('dblclick', function(event) {
- clearTimeout(clickTimeout);
- ishidePopupEnabled = true;
- hidePopup();
- });
- backdrop.addEventListener('click', function(event) {
- if (clickTimeout) clearTimeout(clickTimeout);
- clickTimeout = setTimeout(function() {
- ResetGeometry();
- if (isScale) {
- isScale = false;
- isScaleTL = false;
- isScaleTR = false;
- isScaleBL = false;
- isScaleBR = false;
- ScalingMode0();
- } else if (isLockedY) {
- isLockedY = false;
- popupContainer.style.border = '';
- } else {
- 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 {
- document.querySelectorAll('.popup-container').forEach(e => e.remove());
- document.querySelectorAll('.popup-backdrop').forEach(e => e.remove());
- document.querySelectorAll('.specialElement').forEach(e => e.remove());
- }
- }
- let hoverTimeout;
- indicatorBar.addEventListener('mouseenter', () => {
- hoverTimeout = setTimeout(toggleIndicator, 500);
- });
- indicatorBar.addEventListener('mouseleave', () => {
- clearTimeout(hoverTimeout);
- indicatorBar.style.background = '#0000';
- });
- if (enableP === 1) {
- HoverZoomMinus();
- }
- } else {
- return;
- }
- })();