Drag-Drop Image Uploader

Enables image uploading by simply dragging and dropping images onto a fixed div in the bottom right corner of the page. Easily upload and use images on any website with this convenient script.

当前为 2023-05-21 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Drag-Drop Image Uploader
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.1.5
  5. // @description Enables image uploading by simply dragging and dropping images onto a fixed div in the bottom right corner of the page. Easily upload and use images on any website with this convenient script.
  6. // @match https://*/*
  7. // @grant none
  8. // @license MIT License
  9. // @author CY Fung
  10. // @run-at document-start
  11. // ==/UserScript==
  12.  
  13. (function () {
  14. 'use strict';
  15.  
  16. if (location.hostname === 'lihkg.com') {
  17.  
  18. if (location.pathname !== '/robots.txt') return;
  19. if (window.name !== 'pNwjxjQi') return;
  20. if (window === top) return;
  21.  
  22. function T(e) {
  23. return new Promise(function (resolve, reject) {
  24. window.history.replaceState(null, '', 'https://lihkg.com');
  25. let xhr = new XMLHttpRequest();
  26. let formData = new FormData();
  27. formData.append('image', e);
  28. xhr.open('POST', 'https://api.na.cx/upload');
  29.  
  30. // Set the Referer header to an empty string
  31. xhr.onreadystatechange = function () {
  32. if (xhr.readyState === 4) {
  33. if (xhr.status === 200) {
  34. let response = JSON.parse(xhr.responseText);
  35. let status = response.status;
  36. let url = response.url;
  37. let error = response.error;
  38.  
  39. if (status === 200) {
  40. resolve(url);
  41. } else {
  42. reject(new Error(error));
  43. }
  44. } else {
  45. reject(new Error('Status is not 200'));
  46. }
  47. }
  48. };
  49.  
  50. xhr.send(formData);
  51. });
  52. }
  53.  
  54.  
  55. let iframe = document;
  56.  
  57. // Function to handle the dragenter event
  58. function handleDragEnter(e) {
  59. top.postMessage('pNwjxjQi-top-dragenter', '*');
  60. // Add a class to visually indicate the drag over the iframe
  61. //iframe.classList.add("drag-over");
  62. }
  63.  
  64. // Function to handle the dragover event
  65. function handleDragOver(e) {
  66. // top.postMessage('pNwjxjQi-top-dragover','*');
  67. e.preventDefault();
  68. e.dataTransfer.dropEffect = 'copy';
  69. }
  70.  
  71. // Function to handle the dragleave event
  72. function handleDragLeave(e) {
  73. top.postMessage('pNwjxjQi-top-dragleave', '*');
  74. // Remove the class when the drag leaves the iframe
  75. //iframe.classList.remove("drag-over");
  76. }
  77.  
  78. async function goUpload(e) {
  79.  
  80. let files = e.dataTransfer.files;
  81. let images = [...files].filter(file => file.type == "image/png" || file.type == "image/jpg" || file.type == "image/jpeg" || file.type == "image/gif")
  82. console.log(images);
  83.  
  84. for (const image of images) {
  85. await T(image)
  86. .then(function (url) {
  87. // focusElement.focus();
  88. // document.execCommand("insertText", false, url)
  89. top.postMessage({ p: 'pNwjxjQi-top-finish-upload', url: url }, '*')
  90. console.log('Uploaded image URL:', url);
  91. })
  92. .catch(function (error) {
  93. console.error('Upload failed:', error);
  94. });
  95. }
  96.  
  97. }
  98.  
  99. // Function to handle the drop event
  100. function handleDrop(e) {
  101. e.preventDefault();
  102. top.postMessage('pNwjxjQi-top-drop', '*');
  103.  
  104. // Remove the class when the drop occurs
  105. //iframe.classList.remove("drag-over");
  106.  
  107. // Access the dropped files or data
  108.  
  109. goUpload(e);
  110.  
  111. // Process the dropped files or data as needed
  112. // ...
  113. }
  114. // Add event listeners for drag and drop events
  115. iframe.addEventListener("dragenter", handleDragEnter, false);
  116. iframe.addEventListener("dragover", handleDragOver, false);
  117. iframe.addEventListener("dragleave", handleDragLeave, false);
  118. iframe.addEventListener("drop", handleDrop, false);
  119.  
  120.  
  121. top.postMessage('pNwjxjQi-top-uploader-ready', '*');
  122.  
  123.  
  124. } else {
  125.  
  126. function onReady() {
  127.  
  128. let fixedDiv = null;
  129.  
  130. let focusElement = null;
  131.  
  132. let moused = false;
  133.  
  134. let lastDragIn = 0;
  135. let cid = 0;
  136.  
  137.  
  138. function createFixedDiv() {
  139.  
  140.  
  141. // Create the fixed div element
  142. let fixedDiv = document.createElement('div');
  143. fixedDiv.style.position = 'fixed';
  144. fixedDiv.style.zIndex = '8888';
  145. fixedDiv.style.bottom = '10px';
  146. fixedDiv.style.right = '10px';
  147. fixedDiv.style.width = '200px';
  148. fixedDiv.style.height = '200px';
  149. fixedDiv.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
  150. fixedDiv.style.border = '2px solid white';
  151. fixedDiv.style.borderRadius = '5px';
  152. fixedDiv.style.padding = '0px';
  153. fixedDiv.style.color = 'white';
  154. fixedDiv.style.fontSize = '14px';
  155. fixedDiv.style.textAlign = 'center';
  156. // fixedDiv.style.cursor = 'move';
  157. // fixedDiv.draggable = true;
  158. fixedDiv.style.opacity = '0'; // Set initial opacity to 0 (hidden)
  159. fixedDiv.style.display = 'none';
  160. fixedDiv.id = 'ewIMf5Dw';
  161. fixedDiv.style.background = 'url(https://static.thenounproject.com/png/3905046-200.png)';
  162. fixedDiv.style.backgroundPosition = 'center';
  163. fixedDiv.style.backgroundSize = 'cover';
  164. fixedDiv.style.backgroundRepeat = 'no-repeat';
  165.  
  166. fixedDiv.style.pointerEvents = 'none';
  167.  
  168. // Append the div to the document body
  169. document.body.appendChild(fixedDiv);
  170.  
  171. // Create the Intersection Observer
  172. let observer = new IntersectionObserver(function (entries) {
  173. entries.forEach(function (entry) {
  174. if (entry.isIntersecting) {
  175. // When fixedDiv appears, check if it has an iframe inside
  176. let iframe = fixedDiv.querySelector('iframe');
  177. if (!iframe) {
  178. // If no iframe inside, create and append one
  179. iframe = document.createElement('iframe');
  180. setupIframe(iframe);
  181. iframe.src = 'https://lihkg.com/robots.txt';
  182. fixedDiv.appendChild(iframe);
  183. }
  184. }
  185. });
  186. });
  187.  
  188. // Observe the fixedDiv element
  189. observer.observe(fixedDiv);
  190.  
  191. return fixedDiv;
  192. }
  193. function setupIframe(iframe) {
  194. if (!fixedDiv) return;
  195. iframe.name = 'pNwjxjQi';
  196.  
  197. iframe.style.position = 'relative';
  198. iframe.style.width = '100%';
  199. iframe.style.height = '100%';
  200. iframe.style.opacity = '0';
  201. iframe.style.pointerEvents = 'all';
  202. iframe.style.transform = 'translateY(-300vh)';
  203. fixedDiv.style.transform = 'translateY(-300vh)';
  204.  
  205. }
  206.  
  207.  
  208.  
  209.  
  210. document.addEventListener('dragleave', function (event) {
  211. if (!fixedDiv) return;
  212. if (moused) return;
  213.  
  214. if (cid > 0) cid = clearTimeout(cid);
  215. if (event.relatedTarget) return;
  216. console.log(221);
  217.  
  218. let endTime = Date.now();
  219. cid = setTimeout(() => {
  220. cid = 0;
  221. requestAnimationFrame(() => {
  222. if (lastDragIn > endTime) return;
  223.  
  224. if (fixedDiv.style.display !== 'none' && !moused) {
  225.  
  226. // focusElement = null;
  227. fixedDiv.style.display = 'none';
  228. fixedDiv.style.opacity = '0';
  229. }
  230. });
  231. }, 80)
  232.  
  233. event.preventDefault();
  234.  
  235. });
  236.  
  237. document.addEventListener('dragenter', function (event) {
  238. if (!fixedDiv) fixedDiv = createFixedDiv();
  239. if (moused) return;
  240. if (cid > 0) cid = clearTimeout(cid);
  241. if (event.relatedTarget) return;
  242. console.log(222);
  243.  
  244.  
  245. lastDragIn = Date.now();
  246.  
  247. let activeNode = document.activeElement || 0;
  248. let activeNodeName = activeNode.nodeName;
  249. if (activeNodeName === 'TEXTAREA' || (activeNodeName === 'INPUT' && (!activeNode.type || activeNode.type == 'text'))) {
  250. if (fixedDiv.style.display === 'none') {
  251. fixedDiv.style.display = 'block';
  252. fixedDiv.style.opacity = '0.4';
  253. focusElement = activeNode;
  254. console.log(focusElement)
  255. }
  256. }
  257.  
  258. requestAnimationFrame(() => {
  259.  
  260. lastDragIn = Date.now();
  261. });
  262. }, true);
  263.  
  264. document.addEventListener('drop', function (event) {
  265. if (!fixedDiv) return;
  266. moused = false;
  267. if (moused) return;
  268. if (cid > 0) cid = clearTimeout(cid);
  269. console.log(223);
  270.  
  271. let endTime = Date.now();
  272. cid = setTimeout(() => {
  273. cid = 0;
  274. if (lastDragIn > endTime) return;
  275. if (fixedDiv.style.display !== 'none' && !moused) {
  276. // focusElement = null;
  277.  
  278. fixedDiv.style.display = 'none';
  279. fixedDiv.style.opacity = '0';
  280. }
  281. }, 80)
  282.  
  283.  
  284. }, true);
  285.  
  286.  
  287.  
  288. window.addEventListener('message', event => {
  289. if (!fixedDiv) return;
  290.  
  291. let data = (((event || 0).data || 0));
  292.  
  293.  
  294. if (data === 'pNwjxjQi-top-uploader-ready') {
  295.  
  296. let fixedDiv = document.querySelector('#ewIMf5Dw');
  297. let iframe = fixedDiv.querySelector('iframe');
  298.  
  299. iframe.style.transform = '';
  300. fixedDiv.style.transform = '';
  301.  
  302. }
  303.  
  304. if (data === 'pNwjxjQi-top-dragenter') {
  305. moused = true;
  306. fixedDiv.style.opacity = '1';
  307. }
  308. if (data === 'pNwjxjQi-top-dragleave') {
  309. moused = false;
  310. fixedDiv.style.opacity = '0.4';
  311. }
  312.  
  313. if (data === 'pNwjxjQi-top-dragenter') {
  314.  
  315. if (cid > 0) cid = clearTimeout(cid);
  316. }
  317.  
  318. if (data === 'pNwjxjQi-top-dragleave') {
  319.  
  320. let endTime = Date.now();
  321. if (cid > 0) cid = clearTimeout(cid);
  322. cid = setTimeout(() => {
  323. cid = 0;
  324. requestAnimationFrame(() => {
  325. if (lastDragIn > endTime) return;
  326.  
  327. if (fixedDiv.style.display !== 'none' && !moused) {
  328.  
  329. // focusElement = null;
  330. fixedDiv.style.display = 'none';
  331. fixedDiv.style.opacity = '0';
  332. }
  333. });
  334. }, 80)
  335.  
  336. }
  337.  
  338. if (data.p === 'pNwjxjQi-top-finish-upload') {
  339. let url = event.data.url;
  340. focusElement.focus();
  341. document.execCommand("insertText", false, url)
  342. }
  343.  
  344. if (data === 'pNwjxjQi-top-drop') {
  345. moused = false;
  346.  
  347. let endTime = Date.now();
  348. cid = setTimeout(() => {
  349. cid = 0;
  350. if (lastDragIn > endTime) return;
  351. if (fixedDiv.style.display !== 'none' && !moused) {
  352. // focusElement = null;
  353.  
  354. fixedDiv.style.display = 'none';
  355. fixedDiv.style.opacity = '0';
  356. }
  357. }, 80)
  358. }
  359.  
  360. })
  361.  
  362. }
  363. if (document.readyState !== 'loading') {
  364. onReady();
  365. } else {
  366. document.addEventListener('DOMContentLoaded', onReady, false);
  367. }
  368.  
  369.  
  370.  
  371. }
  372. })();