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