Hover Zoom Minus --

image popup: zoom, pan, scroll, pin, scale

当前为 2024-03-23 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Hover Zoom Minus --
  3. // @namespace Hover Zoom Minus --
  4. // @version 1.0.7.1
  5. // @description image popup: zoom, pan, scroll, pin, scale
  6. // @author Ein, Copilot AI
  7. // @match *://*/*
  8. // @license MIT
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. // 01. to use hover over the image(container) to view a popup of the target image
  13. // 02. to zoom in/out use wheel up/down.
  14. // 03. click left mouse to lock popup this will make it move along with the mouse, click again to release (indicated by green border)
  15. // 04. while being locked"Y" the wheel up/down will act as scroll up/down
  16. // 05. double click will lock it on screen preventing it from being hidden
  17. // 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
  18. // 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
  19. // 08. double clicking on blurred background will de-spawn popup
  20. // 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
  21. // 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
  22. // 11. to turn on/off hover at the bottom of the page
  23.  
  24. (function() {
  25. 'use strict';
  26.  
  27. // Configuration ----------------------------------------------------------
  28.  
  29. // Define regexp of web page you want HoverZoomMinus to run with,
  30. // 1st array value - default status at start of page: '1' for on, '0' for off
  31. // 2nd array value - spawn position for popup: 'center' for center of screen, '' for cursor position
  32. // 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
  33.  
  34. const siteConfig = {
  35. 'reddit.com': [1, 'center', '0'],
  36. '9gag.com': [1, 'center', '0'],
  37. 'feedly.com': [1, 'center', '200'],
  38. '4chan.org': [1, '', '400'],
  39. 'deviantart.com': [0, 'center', '300'],
  40. 'home': [1, 'center', '0'] /* for testing */
  41. };
  42.  
  43. // image container [hover box where popup triggers]
  44. const imgContainers = `
  45. /* ------- reddit */ ._3BxRNDoASi9FbGX01ewiLg, ._3Oa0THmZ3f5iZXAQ0hBJ0k > div, ._35oEP5zLnhKEbj5BlkTBUA, ._1ti9kvv_PMZEF2phzAjsGW > div,
  46. /* ------- reddit */ ._28TEYBuEdOuE3kN6UyoKMa div, ._3Oa0THmZ3f5iZXAQ0hBJ0k.WjuR4W-BBrvdtABBeKUMx div, ._3m20hIKOhTTeMgPnfMbVNN,
  47. /* --------- 9gag */ .post-container .post-view > picture,
  48. /* ------- feedly */ .PinableImageContainer, .entryBody,
  49. /* -------- 4chan */ div.post div.file a,
  50. /* --- deviantart */ ._3_LJY, ._2e1g3, ._2SlAD, ._1R2x6
  51. `;
  52. // target img
  53. const imgElements = `
  54. /* ------- reddit */ ._2_tDEnGMLxpM6uOa2kaDB3, ._1dwExqTGJH2jnA-MYGkEL-, ._2_tDEnGMLxpM6uOa2kaDB3._1XWObl-3b9tPy64oaG6fax,
  55. /* --------- 9gag */ .post-container .post-view > picture > img,
  56. /* ------- feedly */ .pinable, .entryBody img,
  57. /* -------- 4chan */ div.post div.file img:nth-child(1), ._3Oa0THmZ3f5iZXAQ0hBJ0k.WjuR4W-BBrvdtABBeKUMx img, div.post div.file .fileThumb img,
  58. /* --- deviantart */ ._3_LJY img, ._2e1g3 img, ._2SlAD img, ._1R2x6 img
  59. `;
  60. // excluded element
  61. const nopeElements = `
  62. /* ------- reddit */ ._2ED-O3JtIcOqp8iIL1G5cg
  63. `;
  64. // AlbumSelector take note that it will only load image that are already in the DOM tree
  65. // example reddit will not include all until you press navigator buttons so most of the time this will only load a few image
  66. // unless you update it via interacting with navigator button thus updating the DOM tree (added new function for navigation it can now update)
  67. let albumSelector = [
  68. /* ---reddit */ { imgElement: '._1dwExqTGJH2jnA-MYGkEL-', albumElements: '._1apobczT0TzIKMWpza0OhL' },
  69. /* ---feedly */ { imgElement: '.entryBody > div > img', albumElements: '.entryBody > div' },
  70. /* ---feedly */ { imgElement: 'div[id^="Article-"] > div > span > img', albumElements: 'div[id^="Article-"]' },
  71. ];
  72.  
  73. // specialElements were if targeted, will call it's paired function
  74. // 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
  75. const specialElements = [
  76. /* --- 4chan */ { selector: 'div.post div.file .fileThumb img', func: SP1 },
  77. /* -- reddit */ { selector: '._1dwExqTGJH2jnA-MYGkEL-', func: SP2 }
  78. ];
  79. // special function triggered when clicking LeftBar/ wheel down in album mode
  80. const specialLeftBar = [
  81. /* -- reddit */ { selector: '._1dwExqTGJH2jnA-MYGkEL-', func: SPL }
  82. ];
  83. // special function triggered when clicking RightBar/ wheel up in album mode
  84. const specialRightBar = [
  85. /* -- reddit */ { selector: '._1dwExqTGJH2jnA-MYGkEL-', func: SPR }
  86. ];
  87. //-------------------------------------------------------------------------
  88. // Special Funtions -------------------------------------------------------
  89.  
  90.  
  91. // 4chan: replaces thumbnail so popup will use the larger version, or if its animated replace it with that
  92. function SP1(imageElement) {
  93. console.log('SP1 called');
  94. const parentElement = imageElement.parentElement;
  95. const href = parentElement.getAttribute('href');
  96. if (parentElement.tagName === 'a') {
  97. if (href.endsWith('.webm')) {
  98. const videoElement = document.createElement('video');
  99. videoElement.src = href;
  100. videoElement.controls = true;
  101. parentElement.replaceChild(videoElement, imageElement);
  102. } else {
  103. imageElement.setAttribute('src', href);
  104. }
  105. } else {
  106. imageElement.setAttribute('src', href);
  107. }
  108. }
  109.  
  110. // reddit: added the label/description of image along with the popup
  111. function SP2(imageElement) {
  112. if (enableP === 0) {
  113. return;
  114. }
  115. let closestElement = imageElement.closest('.m3aNC6yp8RrNM_-a0rrfa, .kcerW9lbT-se3SXd-wp2i');
  116. if (!closestElement) {
  117. return;
  118. }
  119. let descendantElement = closestElement.querySelector('._15nNdGlBIgryHV04IfAfpA');
  120. if (descendantElement) {
  121. document.querySelectorAll('.specialElement').forEach(e => e.remove());
  122. let title = descendantElement.getAttribute('title');
  123. const specialContent = document.createElement('div');
  124. specialContent.className = 'specialElement';
  125. 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;';
  126. specialContent.textContent = title;
  127. document.body.appendChild(specialContent);
  128.  
  129. var specialBackdrop = document.createElement('div');
  130. specialBackdrop.className = 'specialElement';
  131. 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;';
  132. document.body.appendChild(specialBackdrop);
  133.  
  134. } else {
  135. return;
  136. }
  137. }
  138. function SPL(imageElement) {
  139. document.querySelectorAll('.specialElement').forEach(e => e.remove());
  140.  
  141. let closestElement = imageElement.closest('.kcerW9lbT-se3SXd-wp2i');
  142. var element = closestElement.querySelector('._1fSFPkxZ9pToLETLQT2dmc');
  143. if (element) element.click();
  144.  
  145. let descendantElement = closestElement.querySelector('._15nNdGlBIgryHV04IfAfpA');
  146. if (descendantElement) {
  147. let title = descendantElement.getAttribute('title');
  148. const specialContent = document.createElement('div');
  149. specialContent.className = 'specialElement';
  150. 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;';
  151. specialContent.textContent = title;
  152. document.body.appendChild(specialContent);
  153.  
  154. var specialBackdrop = document.createElement('div');
  155. specialBackdrop.className = 'specialElement';
  156. 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;';
  157. document.body.appendChild(specialBackdrop);
  158. } else {
  159. return;
  160. }
  161. }
  162. function SPR(imageElement) {
  163. document.querySelectorAll('.specialElement').forEach(e => e.remove());
  164.  
  165. let closestElement = imageElement.closest('.kcerW9lbT-se3SXd-wp2i');
  166. var element = closestElement.querySelector('._3-JCOd-nY76g29C7ZVX_kl:last-child');
  167. if (element) element.click();
  168.  
  169. let descendantElement = closestElement.querySelector('._15nNdGlBIgryHV04IfAfpA');
  170. if (descendantElement) {
  171. let title = descendantElement.getAttribute('title');
  172. const specialContent = document.createElement('div');
  173. specialContent.className = 'specialElement';
  174. 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;';
  175. specialContent.textContent = title;
  176. document.body.appendChild(specialContent);
  177.  
  178. var specialBackdrop = document.createElement('div');
  179. specialBackdrop.className = 'specialElement';
  180. 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;';
  181. document.body.appendChild(specialBackdrop);
  182. } else {
  183. return;
  184. }
  185. }
  186. //-------------------------------------------------------------------------
  187.  
  188.  
  189. // Configuration variables
  190. const currentHref = window.location.href;
  191. let enableP, positionP, intervalP, URLmatched;
  192. Object.keys(siteConfig).some((config) => {
  193. const regex = new RegExp(config);
  194. if (currentHref.match(regex)) {
  195. [enableP, positionP, intervalP] = siteConfig[config];
  196. URLmatched = true;
  197. return true;
  198. }
  199. });
  200.  
  201.  
  202. // The HoverZoomMinus Function---------------------------------------------
  203. function HoverZoomMinus() {
  204. let isshowPopupEnabled = true;
  205. isshowPopupEnabled = true;
  206.  
  207. const style = document.createElement('style');
  208. style.type = 'text/css';
  209. style.innerHTML = `
  210. .popup-container {
  211. display: none;
  212. z-index: 1001;
  213. cursor: move;
  214. }
  215. .popup-image {
  216. max-height: calc(90vh - 10px);
  217. display: none;
  218. }
  219. .popup-backdrop {
  220. position: fixed;
  221. top: 0;
  222. left: 0;
  223. width: 100vw;
  224. height: 100vh;
  225. display: none;
  226. z-index: 1000;
  227. }
  228. .centerBox {
  229. top: 40px;
  230. left: 40px;
  231. position: absolute;
  232. height: calc(100% - 80px);
  233. width: calc(100% - 80px);
  234. }
  235. .TopBar,
  236. .BottomBar,
  237. .LeftBar,
  238. .RightBar {
  239. opacity: 0;
  240. box-sizing: border-box;
  241. background: #0000;
  242. position: absolute;
  243. z-index: 9999;
  244. &::after {
  245. content: "";
  246. position: absolute;
  247. }
  248. }
  249. .TopBar,
  250. .BottomBar {
  251. height: 40px;
  252. width: calc(100% - 80px);
  253. left: 40px;
  254. &::after {
  255. display: none;
  256. width: 25px;
  257. height: 25px;
  258. transform: rotate(45deg) translateX(-50%) translateY(-50%);
  259. }
  260. }
  261. .TopBar { top: 0; }
  262. .BottomBar { bottom: 0; }
  263. .TopBar::after {
  264. left: calc(50% - 17px);
  265. top: calc(50% + 15px);
  266. border-top: 5px solid #6f8e9e;
  267. border-left: 5px solid #6f8e9e;
  268. }
  269. .BottomBar::after {
  270. left: calc(50% - 2px);
  271. bottom: -8px;
  272. border-bottom: 5px solid #6f8e9e;
  273. border-right: 5px solid #6f8e9e;
  274. }
  275. .LeftBar,
  276. .RightBar {
  277. height: calc(100% - 80px);
  278. width: 40px;
  279. top: 40px;
  280. &::before {
  281. content: "";
  282. display: block;
  283. position: absolute;
  284. top: 50%;
  285. width: 40px;
  286. height: 40px;
  287. transform: translateY(-50%);
  288. border-radius: 9999px;
  289. background: #242526;
  290. }
  291. &::after {
  292. content: "";
  293. display: block;
  294. position: absolute;
  295. top: calc(50% + -2px);
  296. width: 15px;
  297. height: 15px;
  298. }
  299. &:hover::before {
  300. display: none;
  301. }
  302. &:hover::after {
  303. width: 25px;
  304. height: 25px;
  305. border-color: #6f8e9e;
  306. border-width: 5px;
  307. }
  308. }
  309. .LeftBar { left: 0; }
  310. .RightBar { right: 0; }
  311. .LeftBar::before { left: 5px; }
  312. .RightBar::before { right: 5px; }
  313. .LeftBar:hover::after { left: 3px; }
  314. .RightBar:hover::after { right: 3px; }
  315. .LeftBar::after {
  316. transform: rotate(45deg) translateY(-50%);
  317. border-bottom: 3px solid #777;
  318. border-left: 3px solid #777;
  319. left: 12px;
  320. }
  321. .RightBar::after {
  322. transform: rotate(-45deg) translateY(-50%);
  323. border-bottom: 3px solid #777;
  324. border-right: 3px solid #777;
  325. right: 12px;
  326. }
  327. .CornerBox {
  328. box-sizing: border-box;
  329. height: 40px;
  330. width: 40px;
  331. background: #0000;
  332. position: absolute;
  333. z-index: 9999;
  334. }
  335. .CornerBox.TR {
  336. top: 0;
  337. right: 0;
  338. font-size: 11px;
  339. text-align: center;
  340. line-height: 25px;
  341. color:white;
  342. text-shadow:0 0 4px rgba(255,255,255,0.7);
  343. }
  344. .CornerBox.TL {
  345. top: 0;
  346. left: 0;
  347. }
  348. .CornerBox.BR {
  349. bottom: 0;
  350. right: 0;text-align: center;
  351. }
  352. .CornerBox.BL {
  353. bottom: 0;
  354. left: 0;
  355. }
  356. `;
  357.  
  358. document.head.appendChild(style);
  359. const backdrop = document.createElement('div');
  360. backdrop.className = 'popup-backdrop';
  361. document.body.appendChild(backdrop);
  362. const popupContainer = document.createElement('div');
  363. popupContainer.className = 'popup-container';
  364. document.body.appendChild(popupContainer);
  365. const popup = document.createElement('img');
  366. popup.className = 'popup-image';
  367. popupContainer.appendChild(popup);
  368.  
  369. const BottomBar = document.createElement('div');
  370. BottomBar.className = 'BottomBar';
  371. popupContainer.appendChild(BottomBar);
  372. const TopBar = document.createElement('div');
  373. TopBar.className = 'TopBar';
  374. popupContainer.appendChild(TopBar);
  375. const RightBar = document.createElement('div');
  376. RightBar.className = 'RightBar';
  377. popupContainer.appendChild(RightBar);
  378. const LeftBar = document.createElement('div');
  379. LeftBar.className = 'LeftBar';
  380. popupContainer.appendChild(LeftBar);
  381.  
  382. const TR = document.createElement('div');
  383. TR.className = 'CornerBox TR';
  384. popupContainer.appendChild(TR);
  385. const TL = document.createElement('div');
  386. TL.className = 'CornerBox TL';
  387. popupContainer.appendChild(TL);
  388. const BR = document.createElement('div');
  389. BR.className = 'CornerBox BR';
  390. popupContainer.appendChild(BR);
  391. const BL = document.createElement('div');
  392. BL.className = 'CornerBox BL';
  393. popupContainer.appendChild(BL);
  394.  
  395. const centerBox = document.createElement('div');
  396. centerBox.className = 'popup centerBox';
  397. popupContainer.appendChild(centerBox);
  398.  
  399. const style2 = document.createElement('style');
  400. style2.type = 'text/css';
  401. document.head.appendChild(style2);
  402.  
  403. //-------------------------------------------------------------------------
  404.  
  405. // Variable
  406. const ZOOM_SPEED = 0.005;
  407. let pageDirection;
  408. let isLockedY = false;
  409. let isLockedX = false;
  410. let scale = 1;
  411. let clickTimeout;
  412. let popupTimer;
  413. let isScale, isScaleTR, isScaleBR, isScaleTL, isScaleBL;
  414. let rect, rectT, rectH, rectL, rectW;
  415. let rectIH, rectIW, rectIT, rectIL, rectIRatio;
  416. let rectzT, rectzH, rectzL, rectzW, rectzRatio;
  417. let scaleCurrentX, scaleCurrentY;
  418. let scaleFactorX, scaleFactorY;
  419. let offsetX, offsetY, offsetXR, offsetYT, offsetXL, offsetYB;
  420. let offsetRatioY, offsetRatioX;
  421. let ishidePopupEnabled = true;
  422. let ScaleMode2 = false;
  423. let imgElementsList = [];
  424. let currentZeroImgElement;
  425. let rectIzRatio;
  426.  
  427. function NoMode() {
  428. isLockedY = false;
  429. isLockedX = false;
  430. isScale = false;
  431. isScaleTR = false;
  432. isScaleTL = false;
  433. isScaleBL = false;
  434. isScaleBR = false;
  435. popupContainer.style.border = '';
  436. TR.style.border = '';
  437. BR.style.border = '';
  438. TL.style.border = '';
  439. BL.style.border = '';
  440. }
  441.  
  442. function LockedYMode() {
  443. NoMode();
  444. isLockedY = true;
  445. popupContainer.style.borderLeft = '6px solid #00ff00';
  446. popupContainer.style.borderRight = '6px solid #00ff00';
  447. LeftBar.style.opacity = '0';
  448. RightBar.style.opacity = '0';
  449. }
  450. function LockedXMode() {
  451. NoMode();
  452. LockedScreen();
  453. isLockedX = true;
  454. popupContainer.style.borderTop = '6px solid #00ff00';
  455. popupContainer.style.borderBottom = '6px solid #00ff00';
  456. LeftBar.style.opacity = '1';
  457. RightBar.style.opacity = '1';
  458. style2.innerHTML = `
  459. .LeftBar::before,
  460. .LeftBar::after,
  461. .RightBar::before,
  462. .RightBar::after {
  463. display: block;
  464. }
  465. `;
  466. }
  467.  
  468. function toggleLockedScreen(event) {
  469. ishidePopupEnabled = !ishidePopupEnabled;
  470. popupContainer.style.outline = ishidePopupEnabled ? '' : '6px solid #ae0001';
  471. }
  472.  
  473. function LockedScreen() {
  474. ishidePopupEnabled = false;
  475. popupContainer.style.outline = '6px solid #ae0001';
  476. }
  477. function ScalingMode1() {
  478. TL.style.borderTop = '6px solid #0000ff';
  479. TR.style.borderTop = '6px solid #0000ff';
  480. TL.style.borderLeft = '6px solid #0000ff';
  481. BL.style.borderLeft = '6px solid #0000ff';
  482. TR.style.borderRight = '6px solid #0000ff';
  483. BR.style.borderRight = '6px solid #0000ff';
  484. BR.style.borderBottom = '6px solid #0000ff';
  485. BL.style.borderBottom = '6px solid #0000ff';
  486. }
  487. function ScalingMode2() {
  488. ScalingMode1();
  489. TL.style.borderColor = '#ff00ff';
  490. TR.style.borderColor = '#ff00ff';
  491. BL.style.borderColor = '#ff00ff';
  492. BR.style.borderColor = '#ff00ff';
  493. }
  494. function ScalingMode0() {
  495. TL.style.border = '';
  496. TR.style.border = '';
  497. BL.style.border = '';
  498. BR.style.border = '';
  499. }
  500.  
  501. function ResetGeometry() {
  502. let rectF = popup.getBoundingClientRect();
  503. rectzH = rectF.height;
  504. rectzW = rectF.width;
  505. rectzT = rectF.top;
  506. rectzL = rectF.left;
  507. popup.style.maxHeight = rectzH + 'px';
  508. popup.style.height = rectzH + 'px';
  509. popup.style.width = rectzW + 'px';
  510. popupContainer.style.top = rectzT + (rectzH / 2) + 'px';
  511. popupContainer.style.left = rectzL + (rectzW / 2) + 'px';
  512. popupContainer.style.transformOrigin = '50% 50% 0px';
  513. popupContainer.style.transform = `translate(-50%, -50%) scaleX(1) scaleY(1)`;
  514. }
  515.  
  516. function BarClear() {
  517. TL.style.border = '';
  518. TR.style.border = '';
  519. BL.style.border = '';
  520. BR.style.border = '';
  521. TL.style.background = '';
  522. TR.style.background = '';
  523. BL.style.background = '';
  524. BR.style.background = '';
  525. TopBar.style.background = '';
  526. LeftBar.style.background = '';
  527. RightBar.style.background = '';
  528. BottomBar.style.background = '';
  529. popupContainer.style.border = '';
  530. LeftBar.style.opacity = '0';
  531. RightBar.style.opacity = '0';
  532. }
  533.  
  534.  
  535. function NavigateAlbum() {
  536. let pair = albumSelector.find(pair => currentZeroImgElement.matches(pair.imgElement));
  537. if (pair) {
  538. let ancestorElement = currentZeroImgElement.closest(pair.albumElements);
  539. if (ancestorElement) {
  540. imgElementsList = Array.from(ancestorElement.querySelectorAll(pair.imgElement));
  541. let zeroIndex = imgElementsList.indexOf(currentZeroImgElement);
  542. let direction = pageDirection;
  543. let newIndex = zeroIndex + direction;
  544.  
  545. TR.textContent = `${newIndex + 1}/${imgElementsList.length}`;
  546.  
  547. if (newIndex <= 0) {
  548. LeftBar.style.display = 'none';
  549. TR.textContent = `1/${imgElementsList.length}`;
  550. } else {
  551. LeftBar.style.display = '';
  552. }
  553. if (newIndex >= imgElementsList.length - 1) {
  554. RightBar.style.display = 'none';
  555. TR.textContent = `${imgElementsList.length}/${imgElementsList.length}`;
  556. } else {
  557. RightBar.style.display = '';
  558. }
  559. if (newIndex < 0 || newIndex >= imgElementsList.length) {
  560. return;
  561. }
  562. currentZeroImgElement = imgElementsList[newIndex];
  563. popup.src = currentZeroImgElement.src;
  564. }
  565. }
  566. }
  567.  
  568.  
  569.  
  570.  
  571. // Mouse Click: Center
  572. centerBox.addEventListener('click', function(event) {
  573. if (clickTimeout) clearTimeout(clickTimeout);
  574. clickTimeout = setTimeout(function() {
  575. ResetGeometry();
  576. if (!isScale) {
  577. isLockedY = !isLockedY;
  578. }
  579. if (isLockedY) {
  580. LockedYMode();
  581. let rect = popupContainer.getBoundingClientRect();
  582. offsetX = event.clientX - rect.left - (rect.width / 2);
  583. offsetY = event.clientY - rect.top - (rect.height / 2);
  584. } else {
  585. NoMode();
  586. }
  587. }, 300);
  588. });
  589.  
  590. centerBox.addEventListener('dblclick', function(event) {
  591. clearTimeout(clickTimeout);
  592. toggleLockedScreen();
  593. if (!ishidePopupEnabled) {
  594. backdrop.style.display = 'block';
  595. backdrop.style.zIndex = '999';
  596. backdrop.style.backdropFilter = 'blur(10px)';
  597. }
  598. });
  599. //-------------------------------------------------------------------------
  600.  
  601. // Mouse Click: Corners
  602. document.querySelectorAll('.CornerBox').forEach(element => {
  603. element.addEventListener('click', function(event) {
  604. ishidePopupEnabled = false;
  605. if (isScale) {
  606. BarClear();
  607. isLockedY = false;
  608. isLockedX = false;
  609. popup.style.border = '';
  610.  
  611. const clickedElement = event.target;
  612. const popupContainer = clickedElement.parentElement;
  613. const currentTransform = window.getComputedStyle(popupContainer).transform;
  614. const matrixMatch = currentTransform.match(/^matrix\(([^,]+), [^,]+, [^,]+, ([^,]+), [^,]+, [^,]+\)$/);
  615. if (matrixMatch) {
  616. scaleCurrentX = parseFloat(matrixMatch[1]);
  617. scaleCurrentY = parseFloat(matrixMatch[2]);
  618. }
  619.  
  620. let rect = popupContainer.getBoundingClientRect();
  621. offsetYT = event.clientY - rect.top;
  622. offsetXL = event.clientX - rect.left;
  623. offsetYB = rect.height + rect.top - event.clientY;
  624. offsetXR = rect.width + rect.left - event.clientX;
  625.  
  626. rectT = rect.top;
  627. rectL = rect.left;
  628. rectH = rect.height;
  629. rectW = rect.width;
  630.  
  631. } else {
  632. LockedScreen();
  633. ResetGeometry();
  634. }
  635.  
  636. });
  637. });
  638. document.querySelectorAll('.CornerBox').forEach(element => {
  639. element.addEventListener('click', function(event) {
  640. if (clickTimeout) clearTimeout(clickTimeout);
  641. isScale = !isScale;
  642. }, 300);
  643. });
  644. document.querySelectorAll('.CornerBox').forEach(element => {
  645. element.addEventListener('dblclick', function(event) {
  646. clearTimeout(clickTimeout);
  647. ScaleMode2 = !ScaleMode2;
  648. });
  649. });
  650.  
  651. TL.addEventListener('click', function(event) {
  652. if (clickTimeout) clearTimeout(clickTimeout);
  653. clickTimeout = setTimeout(function() {
  654. isScaleTL = !isScaleTL;
  655. isScaleTR = false;
  656. isScaleBL = false;
  657. isScaleBR = false;
  658. }, 300);
  659. });
  660. TR.addEventListener('click', function(event) {
  661. if (clickTimeout) clearTimeout(clickTimeout);
  662. clickTimeout = setTimeout(function() {
  663. isScaleTL = false;
  664. isScaleTR = !isScaleTR;
  665. isScaleBL = false;
  666. isScaleBR = false;
  667. }, 300);
  668. });
  669. BL.addEventListener('click', function(event) {
  670. if (clickTimeout) clearTimeout(clickTimeout);
  671. clickTimeout = setTimeout(function() {
  672. isScaleTL = false;
  673. isScaleTR = false;
  674. isScaleBL = !isScaleBL;
  675. isScaleBR = false;
  676. }, 300);
  677. });
  678. BR.addEventListener('click', function(event) {
  679. if (clickTimeout) clearTimeout(clickTimeout);
  680. clickTimeout = setTimeout(function() {
  681. isScaleTL = false;
  682. isScaleTR = false;
  683. isScaleBL = false;
  684. isScaleBR = !isScaleBR;
  685. }, 300);
  686. });
  687.  
  688. //-------------------------------------------------------------------------
  689.  
  690.  
  691. // Mouse Move: Pan, Scale
  692. document.addEventListener('mousemove', function(event) {
  693. // Panning mode: popup locked and follows the mouse
  694. if (isLockedY) {
  695. popupContainer.style.left = (event.clientX - offsetX) + 'px';
  696. popupContainer.style.top = (event.clientY - offsetY) + 'px';
  697. } else if (isScale) {
  698. ScalingMode1();
  699. if (ScaleMode2) {
  700. ScalingMode2();
  701. }
  702. if (isScaleTL) {
  703. popupContainer.style.transformOrigin = '100% 100% 0px';
  704. scaleFactorY = scaleCurrentY * (1 + (rectT - event.clientY + offsetYT) / rectH);
  705. scaleFactorX = scaleCurrentX * (1 + (rectL - event.clientX + offsetXL) / rectW);
  706. } else if (isScaleTR) {
  707. popupContainer.style.transformOrigin = '0 100% 0px';
  708. scaleFactorY = scaleCurrentY * (1 + (rectT - event.clientY + offsetYT) / rectH);
  709. scaleFactorX = scaleCurrentX * ((event.clientX - rectL + offsetXR) / rectW);
  710. } else if (isScaleBL) {
  711. popupContainer.style.transformOrigin = '100% 0% 0px';
  712. scaleFactorY = scaleCurrentY * ((event.clientY - rectT + offsetYB) / rectH);
  713. scaleFactorX = scaleCurrentX * (1 + (rectL - event.clientX + offsetXL) / rectW);
  714. } else if (isScaleBR) {
  715. popupContainer.style.transformOrigin = '0% 0% 0px';
  716. scaleFactorY = scaleCurrentY * ((event.clientY - rectT + offsetYB) / rectH);
  717. scaleFactorX = scaleCurrentX * ((event.clientX - rectL + offsetXR) / rectW);
  718. }
  719. if (ScaleMode2) {
  720. popupContainer.style.transform = `translate(-50%, -50%) scaleX(${scaleFactorX}) scaleY(${scaleFactorY})`;
  721.  
  722. } else {
  723. popupContainer.style.transform = `translate(-50%, -50%) scaleX(${scaleFactorX}) scaleY(${scaleFactorX})`;
  724. }
  725. }
  726. });
  727.  
  728.  
  729. // Mouse Wheel: Zoom, Scroll, Navigate
  730. function ZoomOrScroll(event) {
  731. event.preventDefault();
  732. if (isLockedY) {
  733. let deltaY = event.deltaY * -ZOOM_SPEED;
  734. let newTop = parseInt(popupContainer.style.top) || 0;
  735. newTop += deltaY * 100;
  736. popupContainer.style.top = newTop + 'px';
  737. offsetY -= deltaY * 100;
  738.  
  739. } else if (isLockedX && currentZeroImgElement) {
  740. pageDirection = event.deltaY > 0 ? 1 : -1;
  741. NavigateAlbum();
  742.  
  743. if (pageDirection === 1) {
  744. const imageElement = currentContainer.querySelector(imgElements);
  745. specialRightBar.forEach(pair => {
  746. if (imageElement.matches(pair.selector)) {
  747. pair.func(imageElement);
  748. }
  749. });
  750. } else {
  751. const imageElement = currentContainer.querySelector(imgElements);
  752. specialLeftBar.forEach(pair => {
  753. if (imageElement.matches(pair.selector)) {
  754. pair.func(imageElement);
  755. }
  756. });
  757. }
  758.  
  759. } else {
  760. scale += event.deltaY * -ZOOM_SPEED;
  761. scale = Math.min(Math.max(0.125, scale), 10);
  762. popupContainer.style.transform = `translate(-50%, -50%) scaleX(${scale}) scaleY(${scale})`;
  763. }
  764. }
  765. popupContainer.addEventListener('wheel', ZoomOrScroll);
  766. //-------------------------------------------------------------------------
  767.  
  768.  
  769. // Bottom Bar: Album
  770. BottomBar.addEventListener('mouseenter', function(e) {
  771.  
  772. if (isScale) {
  773. return;
  774. } else {
  775. BottomBar.style.opacity = '1';
  776.  
  777. let rect = popup.getBoundingClientRect();
  778. rectzRatio = rect.height / rect.width;
  779. rectIzRatio = Number(rectIRatio.toFixed(3)) / Number(rectzRatio.toFixed(3));
  780.  
  781. if (isAlbum) {
  782. if (!isScale) {
  783. 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%)';
  784. }
  785. } else {
  786. BottomBar.style.background = '';
  787. if (!( (rectIzRatio === 1) || isScale ) ) {
  788. style2.innerHTML = `
  789. .BottomBar::after {
  790. display: block;
  791. }
  792. `;
  793. BL.style.background = 'rgba(0, 0, 0, 0.5)';
  794. BR.style.background = 'rgba(0, 0, 0, 0.5)';
  795. BottomBar.style.background = 'rgba(0, 0, 0, 0.5)';
  796. } else {
  797. style2.innerHTML = `
  798. .BottomBar::after {
  799. display: none;
  800. }
  801. `;
  802. }
  803. }
  804. }
  805. });
  806.  
  807. BottomBar.addEventListener('mouseleave', function() {
  808. BottomBar.style.opacity = '0';
  809. if (!isLockedX) {
  810. BarClear();
  811. }
  812. });
  813. BottomBar.addEventListener('click', function(event) {
  814. if (clickTimeout) clearTimeout(clickTimeout);
  815. clickTimeout = setTimeout(function() {
  816. if (!isScale) {
  817. LeftBar.style.opacity = '0';
  818. RightBar.style.opacity = '0';
  819. }
  820. if (isAlbum) {
  821. ResetGeometry();
  822. isLockedX = !isLockedX;
  823. if (isLockedX) {
  824. LockedXMode();
  825. LeftBar.style.opacity = '1';
  826. RightBar.style.opacity = '1';
  827. } else {
  828. popupContainer.style.border = '';
  829. }
  830. } else {
  831. ResetGeometry();
  832. if (isScale) {
  833. isScale = false;
  834. popup.style.maxHeight = rectzH + 'px';
  835. popup.style.height = rectzH + 'px';
  836. offsetRatioY = 0;
  837. } else {
  838. popup.style.maxHeight = 'unset';
  839. popup.style.height = '';
  840. offsetRatioY = (rectzH - rectzW * rectIRatio) / 2 ;
  841. }
  842. popupContainer.style.top = rectzT + (rectzH / 2) + offsetRatioY + 'px';
  843. }
  844. }, 300);
  845. });
  846.  
  847.  
  848. BottomBar.addEventListener('dblclick', function(event) {
  849. clearTimeout(clickTimeout);
  850.  
  851. if (isAlbum) {
  852. ResetGeometry();
  853. if (isScale) {
  854. popup.style.maxHeight = rectzH + 'px';
  855. popup.style.height = rectzH + 'px';
  856. offsetRatioY = 0;
  857. } else {
  858. popup.style.maxHeight = 'unset';
  859. popup.style.height = '';
  860. offsetRatioY = (rectzH - rectzW * rectIRatio) / 2 ;
  861. }
  862. popupContainer.style.top = rectzT + (rectzH / 2) + offsetRatioY + 'px';
  863. BarClear();
  864. } else {
  865. return;
  866. }
  867. });
  868. //-------------------------------------------------------------------------
  869.  
  870.  
  871. // Indicators
  872. document.querySelectorAll('.CornerBox').forEach(element => {
  873. element.addEventListener('mouseenter', function(event) {
  874. ScalingMode1();
  875. if (ScaleMode2) {
  876. ScalingMode2();
  877. }
  878. });
  879. element.addEventListener('mouseleave', function(event) {
  880. if (!isScale) {
  881. ScalingMode0();
  882. }
  883. });
  884. });
  885.  
  886. // Re-scale/ Navigate
  887. TopBar.addEventListener('click', function(event) {
  888. if (clickTimeout) clearTimeout(clickTimeout);
  889. clickTimeout = setTimeout(function() {
  890. ResetGeometry();
  891. if (isScale) {
  892. isScale = false;
  893. popup.style.maxHeight = rectzH + 'px';
  894. popup.style.height = rectzH + 'px';
  895. offsetRatioY = 0;
  896. } else {
  897. popup.style.maxHeight = 'unset';
  898. popup.style.height = '';
  899. offsetRatioY = (rectzH - rectzW * rectIRatio) / 2 ;
  900. }
  901. popupContainer.style.top = rectzT + (rectzH / 2) - offsetRatioY + 'px';
  902. BarClear();
  903.  
  904. }, 300);
  905. });
  906.  
  907. TopBar.addEventListener('dblclick', function(event) {
  908. clearTimeout(clickTimeout);
  909. LockedScreen();
  910. });
  911.  
  912.  
  913.  
  914. let zeroIndex;
  915. LeftBar.addEventListener('click', function(event) {
  916. if (clickTimeout) clearTimeout(clickTimeout);
  917. clickTimeout = setTimeout(function() {
  918. ResetGeometry();
  919. if (isScale) {
  920. isScale = false;
  921. popup.style.width = rectzW + 'px';
  922. offsetRatioX = 0;
  923. } else {
  924. popup.style.width = '';
  925. offsetRatioX = (rectzW - (rectzH / rectIRatio)) / 2 ;
  926. }
  927. if (isLockedX && currentZeroImgElement) {
  928. pageDirection = -1;
  929. NavigateAlbum();
  930.  
  931. TL.style.background = 'rgba(0, 0, 0, 0.5)';
  932. BL.style.background = 'rgba(0, 0, 0, 0.5)';
  933. LeftBar.style.background = 'rgba(0, 0, 0, 0.5)';
  934.  
  935. const imageElement = currentContainer.querySelector(imgElements);
  936. specialLeftBar.forEach(pair => {
  937. if (imageElement.matches(pair.selector)) {
  938. pair.func(imageElement);
  939. }
  940. });
  941.  
  942. } else {
  943. popupContainer.style.left = rectzL + (rectzW / 2) - offsetRatioX + 'px';
  944. }
  945. }, 300);
  946. });
  947. RightBar.addEventListener('click', function(event) {
  948. if (clickTimeout) clearTimeout(clickTimeout);
  949. clickTimeout = setTimeout(function() {
  950. ResetGeometry();
  951. if (isScale) {
  952. isScale = false;
  953. popup.style.width = rectzW + 'px';
  954. offsetRatioX = 0;
  955. } else {
  956. popup.style.width = '';
  957. offsetRatioX = (rectzW - (rectzH / rectIRatio)) / 2 ;
  958. }
  959. if (isLockedX && currentZeroImgElement) {
  960. pageDirection = 1;
  961. NavigateAlbum();
  962. TR.style.background = 'rgba(0, 0, 0, 0.5)';
  963. BR.style.background = 'rgba(0, 0, 0, 0.5)';
  964. RightBar.style.background = 'rgba(0, 0, 0, 0.5)';
  965.  
  966. const imageElement = currentContainer.querySelector(imgElements);
  967. specialRightBar.forEach(pair => {
  968. if (imageElement.matches(pair.selector)) {
  969. pair.func(imageElement);
  970. }
  971. });
  972.  
  973. } else {
  974. popupContainer.style.left = rectzL + (rectzW / 2) + offsetRatioX + 'px';
  975. }
  976. }, 300);
  977. });
  978.  
  979.  
  980.  
  981. TopBar.addEventListener('mouseenter', function() {
  982. let rect = popup.getBoundingClientRect();
  983. rectzRatio = rect.height / rect.width;
  984. rectIzRatio = Number(rectIRatio.toFixed(3)) / Number(rectzRatio.toFixed(3));
  985. if (!( (rectIzRatio === 1) || isScale ) ) {
  986. TopBar.style.opacity = '1';
  987. style2.innerHTML = `
  988. .TopBar::after {
  989. display: block;
  990. }`;
  991. TL.style.background = 'rgba(0, 0, 0, 0.5)';
  992. TR.style.background = 'rgba(0, 0, 0, 0.5)';
  993. TopBar.style.background = 'rgba(0, 0, 0, 0.5)';
  994. } else {
  995. style2.innerHTML = `
  996. .TopBar::after {
  997. display: none;
  998. }`;
  999. if (ishidePopupEnabled) {
  1000. TopBar.style.opacity = '1';
  1001. TL.style.background = 'rgba(0, 0, 0, 0.5)';
  1002. TR.style.background = 'rgba(0, 0, 0, 0.5)';
  1003. TopBar.style.background = 'rgba(0, 0, 0, 0.5)';
  1004. }
  1005. }
  1006. });
  1007. LeftBar.addEventListener('mouseenter', function() {
  1008. LeftBar.style.opacity = '1';
  1009. let rect = popup.getBoundingClientRect();
  1010. rectzRatio = rect.height / rect.width;
  1011. rectIzRatio = Number(rectIRatio.toFixed(3)) / Number(rectzRatio.toFixed(3));
  1012. if ( isLockedX || !( (rectIzRatio === 1) || isScale ) ) {
  1013. style2.innerHTML = `
  1014. .LeftBar::before, .LeftBar::after {
  1015. display: block;
  1016. }`;
  1017. TL.style.background = 'rgba(0, 0, 0, 0.5)';
  1018. BL.style.background = 'rgba(0, 0, 0, 0.5)';
  1019. LeftBar.style.background = 'rgba(0, 0, 0, 0.5)';
  1020. } else {
  1021. style2.innerHTML = `
  1022. .LeftBar::before, .LeftBar::after {
  1023. display: none;
  1024. }`;
  1025. }
  1026. });
  1027. RightBar.addEventListener('mouseenter', function() {
  1028. RightBar.style.opacity = '1';
  1029. let rect = popup.getBoundingClientRect();
  1030. rectzRatio = rect.height / rect.width;
  1031. rectIzRatio = Number(rectIRatio.toFixed(3)) / Number(rectzRatio.toFixed(3));
  1032. if ( isLockedX || !( (rectIzRatio === 1) || isScale ) ) {
  1033. style2.innerHTML = `
  1034. .RightBar::before, .RightBar::after {
  1035. display: block;
  1036. }`;
  1037. TR.style.background = 'rgba(0, 0, 0, 0.5)';
  1038. BR.style.background = 'rgba(0, 0, 0, 0.5)';
  1039. RightBar.style.background = 'rgba(0, 0, 0, 0.5)';
  1040. } else {
  1041. style2.innerHTML = `
  1042. .RightBar::before, .RightBar::after {
  1043. display: none;
  1044. }`;
  1045. }
  1046. });
  1047.  
  1048. TopBar.addEventListener('mouseleave', function() {
  1049. TopBar.style.opacity = '0';
  1050. TopBar.style.border = '';
  1051. TL.style.background = '';
  1052. TR.style.background = '';
  1053. TopBar.style.background = '';
  1054. if (isScale) {
  1055. TR.style.borderColor = '#0000ff';
  1056. TL.style.borderColor = '#0000ff';
  1057. if (ScaleMode2) {
  1058. TR.style.borderColor = '#ff00ff';
  1059. TL.style.borderColor = '#ff00ff';
  1060. }
  1061. } else {
  1062. TR.style.border = '';
  1063. TL.style.border = '';
  1064. }
  1065. });
  1066. LeftBar.addEventListener('mouseleave', function() {
  1067. if (isLockedX) {
  1068. LeftBar.style.opacity = '1';
  1069. } else {
  1070. LeftBar.style.opacity = '0';
  1071. }
  1072. TL.style.background = '';
  1073. BL.style.background = '';
  1074. LeftBar.style.background = '';
  1075. });
  1076. RightBar.addEventListener('mouseleave', function() {
  1077. if (isLockedX) {
  1078. RightBar.style.opacity = '1';
  1079. } else {
  1080. RightBar.style.opacity = '0';
  1081. }
  1082. TR.style.background = '';
  1083. BR.style.background = '';
  1084. RightBar.style.background = '';
  1085. });
  1086. //-------------------------------------------------------------------------
  1087.  
  1088.  
  1089. // show popup
  1090. function showPopup(src, mouseX, mouseY) {
  1091. if (!isshowPopupEnabled) return;
  1092. ishidePopupEnabled = true;
  1093. if (enableP === 0) return;
  1094.  
  1095. popup.src = src;
  1096. popup.style.display = 'block';
  1097. popupContainer.style.display = 'block';
  1098. popupContainer.style.position = 'fixed';
  1099. popupContainer.style.transform = 'translate(-50%, -50%) scaleX(1) scaleY(1)';
  1100. backdrop.style.display = 'block';
  1101. backdrop.style.zIndex = '999';
  1102. backdrop.style.backdropFilter = 'blur(10px)';
  1103.  
  1104. if (positionP === 'center') {
  1105. popupContainer.style.top = '50%';
  1106. popupContainer.style.left = '50%';
  1107. } else {
  1108. popupContainer.style.top = `${mouseY}px`;
  1109. popupContainer.style.left = `${mouseX}px`;
  1110. }
  1111.  
  1112. let rectI = popup.getBoundingClientRect();
  1113. rectIH = rectI.height;
  1114. rectIW = rectI.width;
  1115. rectIT = rectI.top;
  1116. rectIL = rectI.left;
  1117.  
  1118. rectIRatio = rectIH / rectIW;
  1119.  
  1120. if (positionP === '') {
  1121. if (mouseY < window.innerHeight * 0.33) {
  1122. console.log('adjust top');
  1123. popupContainer.style.top = mouseY + (rectIH / 2) - 40 + 'px';
  1124. } else if (mouseY >= window.innerHeight * 0.33 && mouseY < window.innerHeight * 0.67) {
  1125. console.log('center Y');
  1126. popupContainer.style.top = mouseY + 'px';
  1127. } else if (mouseY >= window.innerHeight * 0.67) {
  1128. console.log('adjust bottom');
  1129. popupContainer.style.top = mouseY - (rectIH / 2) + 40 + 'px';
  1130. }
  1131. if (mouseX < window.innerWidth * 0.33) {
  1132. console.log('adjust left');
  1133. popupContainer.style.left = mouseX + (rectIW / 2) - 40 + 'px';
  1134. } else if (mouseX >= window.innerWidth * 0.33 && mouseX < window.innerWidth * 0.67) {
  1135. console.log('center X');
  1136. popupContainer.style.left = mouseX + 'px';
  1137. } else if (mouseX >= window.innerWidth * 0.67) {
  1138. console.log('center right');
  1139. popupContainer.style.left = mouseX - (rectIW / 2) + 40 + 'px';
  1140. }
  1141. }
  1142. if (isAlbum) {
  1143. LockedXMode();
  1144. }
  1145.  
  1146. }
  1147.  
  1148. let isAlbum;
  1149. let currentContainer;
  1150. document.addEventListener('mouseover', function(e) {
  1151.  
  1152. if (popupTimer) return;
  1153. let target = e.target.closest(imgContainers);
  1154.  
  1155. console.log('Entered imgContainer:', target);
  1156. if (!target) return;
  1157.  
  1158.  
  1159. if (target.querySelector(nopeElements)) return;
  1160. currentContainer = target;
  1161.  
  1162. const imageElement = currentContainer.querySelector(imgElements);
  1163.  
  1164. specialElements.forEach(pair => {
  1165. if (imageElement.matches(pair.selector)) {
  1166. pair.func(imageElement);
  1167. }
  1168. });
  1169.  
  1170. if (imageElement) {
  1171. currentZeroImgElement = imageElement;
  1172. if (currentZeroImgElement) {
  1173. let pair = albumSelector.find(pair => currentZeroImgElement.matches(pair.imgElement));
  1174.  
  1175. if (pair) {
  1176. let closestAlbumElement = currentZeroImgElement.closest(pair.albumElements);
  1177. isAlbum = closestAlbumElement && closestAlbumElement.querySelectorAll(pair.imgElement).length > 1;
  1178.  
  1179. if (isAlbum) {
  1180. imgElementsList = Array.from(closestAlbumElement.querySelectorAll(pair.imgElement));
  1181. let zeroIndex = imgElementsList.indexOf(currentZeroImgElement);
  1182.  
  1183. TR.textContent = `${zeroIndex + 1}/${imgElementsList.length}`;
  1184.  
  1185. if (zeroIndex === 0) {
  1186. LeftBar.style.display = 'none';
  1187. } else {
  1188. LeftBar.style.display = '';
  1189. }
  1190. if (zeroIndex === imgElementsList.length - 1) {
  1191. RightBar.style.display = 'none';
  1192. } else {
  1193. RightBar.style.display = '';
  1194. }
  1195. }
  1196. } else {
  1197. isAlbum = false;
  1198. TR.textContent = '';
  1199. LeftBar.style.display = '';
  1200. RightBar.style.display = '';
  1201. }
  1202. }
  1203. if (intervalP === '') {
  1204. showPopup(imageElement.src, e.clientX, e.clientY);
  1205. } else {
  1206. popupTimer = setTimeout(() => {
  1207. showPopup(imageElement.src, e.clientX, e.clientY);
  1208. popupTimer = null;
  1209. }, parseInt(intervalP));
  1210. }
  1211. }
  1212. });
  1213. //-------------------------------------------------------------------------
  1214.  
  1215. // hide popup
  1216. function hidePopup() {
  1217. if (!ishidePopupEnabled) return;
  1218. imgElementsList = [];
  1219. if (popupTimer) {
  1220. clearTimeout(popupTimer);
  1221. }
  1222. popup.style.display = 'none';
  1223. popupContainer.style.display = 'none';
  1224.  
  1225. NoMode();
  1226. popup.style.maxHeight = 'calc(90vh - 10px)';
  1227. popup.style.width = '';
  1228. popup.style.height = '';
  1229. popupContainer.style.left = '50%';
  1230. popupContainer.style.top = '50%';
  1231. popupContainer.style.position = 'fixed';
  1232. popupContainer.style.transform = 'translate(-50%, -50%) scaleX(1) scaleY(1)';
  1233. popupContainer.style.transformOrigin = '';
  1234. popupContainer.style.outline = '';
  1235. backdrop.style.zIndex = '';
  1236. backdrop.style.display = 'none';
  1237. backdrop.style.backdropFilter = '';
  1238. LeftBar.style.opacity = '0';
  1239. RightBar.style.opacity = '0';
  1240. style2.innerHTML = `
  1241. .LeftBar::before,
  1242. .LeftBar::after,
  1243. .RighttBar::before,
  1244. .RighttBar::after {
  1245. display: none;
  1246. }`;
  1247. document.querySelectorAll('.specialElement').forEach(e => e.remove());
  1248. }
  1249. popupContainer.addEventListener('mouseout', function(event) {
  1250.  
  1251. let relatedTarget = event.relatedTarget;
  1252. if (relatedTarget && (popupContainer.contains(relatedTarget) || relatedTarget.matches('.imgContainers') || relatedTarget.closest('.imgContainers'))) {
  1253. return;
  1254. }
  1255.  
  1256. document.querySelectorAll('.specialElement').forEach(e => e.remove());
  1257.  
  1258. hidePopup();
  1259. if (intervalP !== '') {
  1260. popupTimer = setTimeout(() => {
  1261. popupTimer = null;
  1262. }, parseInt(intervalP));
  1263. }
  1264. });
  1265. document.addEventListener('keydown', function(event) {
  1266. if (event.key === "Escape") {
  1267. event.preventDefault();
  1268. hidePopup();
  1269. }
  1270. });
  1271. //-------------------------------------------------------------------------
  1272.  
  1273.  
  1274. // lock popup in screen
  1275. backdrop.addEventListener('dblclick', function(event) {
  1276. clearTimeout(clickTimeout);
  1277. ishidePopupEnabled = true;
  1278. hidePopup();
  1279. });
  1280. backdrop.addEventListener('click', function(event) {
  1281. if (clickTimeout) clearTimeout(clickTimeout);
  1282. clickTimeout = setTimeout(function() {
  1283. ResetGeometry();
  1284. if (isScale) {
  1285. isScale = false;
  1286. isScaleTL = false;
  1287. isScaleTR = false;
  1288. isScaleBL = false;
  1289. isScaleBR = false;
  1290. ScalingMode0();
  1291.  
  1292. } else if (isLockedY) {
  1293. isLockedY = false;
  1294. popupContainer.style.border = '';
  1295. } else {
  1296. backdrop.style.zIndex = '';
  1297. backdrop.style.display = 'none';
  1298. backdrop.style.backdropFilter = '';
  1299. isshowPopupEnabled = false;
  1300. }
  1301. }, 300);
  1302. });
  1303.  
  1304. }
  1305. //-------------------------------------------------------------------------
  1306.  
  1307.  
  1308. // Is to be run -----------------------------------------------------------
  1309. if (URLmatched) {
  1310. const indicatorBar = document.createElement('div');
  1311. indicatorBar.style.cssText = `
  1312. position: fixed;
  1313. bottom: 0;
  1314. left: 50%;
  1315. transform: translateX(-50%);
  1316. z-index: 9999;
  1317. height: 30px;
  1318. width: 50vw;
  1319. background: #0000;`;
  1320. document.body.appendChild(indicatorBar);
  1321.  
  1322. function toggleIndicator() {
  1323. enableP = 1 - enableP;
  1324.  
  1325. 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%)';
  1326. setTimeout(() => {
  1327. indicatorBar.style.background = '#0000';
  1328. }, 1000);
  1329. if (enableP === 1) {
  1330. HoverZoomMinus();
  1331. } else {
  1332. document.querySelectorAll('.popup-container').forEach(e => e.remove());
  1333. document.querySelectorAll('.popup-backdrop').forEach(e => e.remove());
  1334. document.querySelectorAll('.specialElement').forEach(e => e.remove());
  1335. }
  1336. }
  1337. let hoverTimeout;
  1338. indicatorBar.addEventListener('mouseenter', () => {
  1339. hoverTimeout = setTimeout(toggleIndicator, 500);
  1340. });
  1341. indicatorBar.addEventListener('mouseleave', () => {
  1342. clearTimeout(hoverTimeout);
  1343. indicatorBar.style.background = '#0000';
  1344. });
  1345. if (enableP === 1) {
  1346. HoverZoomMinus();
  1347. }
  1348. } else {
  1349. return;
  1350. }
  1351.  
  1352. })();