// ==UserScript==
// @name 原生图片浏览器
// @version 2.2
// @description 最优雅的图片打开方式
// @author hiisme
// @match https://image.baidu.com/*
// @match https://unsplash.com/*
// @match https://www.google.com/*
// @grant GM_registerMenuCommand
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_notification
// @namespace https://greasyfork.org/users/217852
// ==/UserScript==
(async function() {
'use strict';
let enableImageClick = await GM_getValue('enableImageClick', true);
let shortcut = await GM_getValue('shortcut', 'Ctrl+Shift+I');
let windowWidth = await GM_getValue('windowWidth', screen.width);
let windowHeight = await GM_getValue('windowHeight', screen.height);
async function toggleImageClick() {
enableImageClick = !enableImageClick;
await GM_setValue('enableImageClick', enableImageClick);
GM_notification({
text: `Image click-to-open feature is now ${enableImageClick ? 'enabled' : 'disabled'}.`,
title: 'Image Viewer',
timeout: 3000
});
}
async function setShortcut() {
const newShortcut = prompt('Enter new shortcut (e.g., Ctrl+Shift+I):', shortcut);
if (newShortcut) {
shortcut = newShortcut;
await GM_setValue('shortcut', shortcut);
GM_notification({
text: `Shortcut set to: ${shortcut}`,
title: 'Image Viewer',
timeout: 3000
});
}
}
async function setWindowSize() {
const newWidth = prompt('Enter new window width (pixels):', windowWidth);
const newHeight = prompt('Enter new window height (pixels):', windowHeight);
if (newWidth && newHeight) {
windowWidth = parseInt(newWidth, 10);
windowHeight = parseInt(newHeight, 10);
await GM_setValue('windowWidth', windowWidth);
await GM_setValue('windowHeight', windowHeight);
GM_notification({
text: `Window size set to: ${windowWidth}x${windowHeight}`,
title: 'Image Viewer',
timeout: 3000
});
}
}
GM_registerMenuCommand("Toggle Image Click-to-Open", toggleImageClick);
GM_registerMenuCommand("Set Shortcut", setShortcut);
GM_registerMenuCommand("Set Window Size", setWindowSize);
function parseShortcut(shortcut, event) {
const keys = shortcut.toLowerCase().split('+').map(k => k.trim());
return keys.includes(event.key.toLowerCase()) &&
(keys.includes('ctrl') === event.ctrlKey) &&
(keys.includes('shift') === event.shiftKey) &&
(keys.includes('alt') === event.altKey) &&
(keys.includes('meta') || keys.includes('cmd') || keys.includes('command') === event.metaKey);
}
function onKeyDown(event) {
if (parseShortcut(shortcut, event)) {
event.preventDefault();
toggleImageClick();
}
}
document.addEventListener('keydown', onKeyDown);
function createImageViewer(url) {
const topOffset = screen.height * 0.05;
const leftOffset = (screen.width - windowWidth) / 2;
const topPosition = (screen.height - windowHeight) / 2 - topOffset;
const newWindow = window.open('', '_blank', `width=${windowWidth},height=${windowHeight},top=${topPosition},left=${leftOffset},resizable=yes,scrollbars=no`);
if (newWindow) {
// Set a minimal HTML structure with inline styles to prevent flicker
newWindow.document.open();
newWindow.document.write(`
<html>
<head>
<style>
body {
margin: 0;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
background: black;
}
img {
max-width: 100vw;
max-height: 100vh;
cursor: grab;
transition: transform 0.1s ease;
position: absolute;
user-drag: none;
-webkit-user-drag: none;
}
</style>
<meta name="theme-color" content="#000000">
</head>
<body>
<img src="${url}" alt="Image" />
</body>
</html>
`);
newWindow.document.close();
let scale = 1;
let imgX = 0, imgY = 0;
let isDragging = false;
let lastMouseX = 0, lastMouseY = 0;
function onMouseMove(event) {
if (isDragging) {
const deltaX = event.clientX - lastMouseX;
const deltaY = event.clientY - lastMouseY;
imgX += deltaX;
imgY += deltaY;
newWindow.document.querySelector('img').style.transform = `translate(${imgX}px, ${imgY}px) scale(${scale})`;
lastMouseX = event.clientX;
lastMouseY = event.clientY;
}
}
function onMouseUp() {
isDragging = false;
newWindow.document.querySelector('img').style.cursor = 'grab';
newWindow.removeEventListener('mousemove', onMouseMove);
newWindow.removeEventListener('mouseup', onMouseUp);
}
function onWheelHandler(event) {
event.preventDefault();
const scaleAmount = event.deltaY > 0 ? 0.9 : 1.1;
scale *= scaleAmount;
newWindow.document.querySelector('img').style.transform = `translate(${imgX}px, ${imgY}px) scale(${scale})`;
}
function onMouseDownHandler(event) {
event.preventDefault();
isDragging = true;
newWindow.document.querySelector('img').style.cursor = 'grabbing';
lastMouseX = event.clientX;
lastMouseY = event.clientY;
newWindow.addEventListener('mousemove', onMouseMove);
newWindow.addEventListener('mouseup', onMouseUp);
}
function onDoubleClickHandler() {
newWindow.close();
}
newWindow.document.body.addEventListener('wheel', onWheelHandler, { passive: false });
newWindow.document.body.addEventListener('mousedown', onMouseDownHandler);
newWindow.document.body.addEventListener('dblclick', onDoubleClickHandler);
newWindow.addEventListener('beforeunload', () => {
newWindow.document.body.removeEventListener('wheel', onWheelHandler);
newWindow.document.body.removeEventListener('mousedown', onMouseDownHandler);
newWindow.document.body.removeEventListener('dblclick', onDoubleClickHandler);
newWindow.removeEventListener('mousemove', onMouseMove);
newWindow.removeEventListener('mouseup', onMouseUp);
});
}
}
async function onClick(event) {
const target = event.target;
if (target.tagName === 'A' && /\.(jpg|jpeg|png|gif|webp)$/i.test(target.href)) {
event.preventDefault();
event.stopPropagation(); // Prevent default behavior and stop further event propagation
createImageViewer(target.href);
} else if (enableImageClick && target.tagName === 'IMG' && /\.(jpg|jpeg|png|gif|webp)$/i.test(target.src)) {
event.preventDefault();
event.stopPropagation(); // Prevent default behavior and stop further event propagation
createImageViewer(target.src);
} else if (enableImageClick && target.tagName === 'IMG' && target.src) {
event.preventDefault();
event.stopPropagation(); // Prevent default behavior and stop further event propagation
createImageViewer(target.src);
}
}
document.addEventListener('click', onClick, true);
function cleanUp() {
document.removeEventListener('keydown', onKeyDown);
document.removeEventListener('click', onClick, true);
}
window.addEventListener('unload', cleanUp);
})();