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.

// ==UserScript==
// @name         Drag-Drop Image Uploader
// @namespace           http://tampermonkey.net/
// @version      0.2.1
// @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.
// @match        https://*/*
// @grant        none
// @license             MIT License
// @author              CY Fung
// @icon                https://raw.githubusercontent.com/cyfung1031/userscript-supports/main/icons/drag-drop-image-uploader.svg
// @run-at       document-start
// ==/UserScript==

(function () {
    'use strict';

    if (location.hostname === 'lihkg.com') {

        if (location.pathname !== '/robots.txt') return;
        if (window.name !== 'pNwjxjQi') return;
        if (window === top) return;


        function T(e) {
            return new Promise(function (resolve, reject) {
                window.history.replaceState(null, '', 'https://lihkg.com');
                let formData = new FormData();
                formData.append('image', e);

                fetch('https://api.na.cx/upload', {
                    method: 'POST',
                    body: formData,

                    "mode": "cors",
                    "credentials": "omit",

                    referrerPolicy: "no-referrer",
                    cache: "default", // no effect on POST request
                    // cache: "force-cache",
                    redirect: "error", // there shall be no redirection in this API request
                    integrity: "",
                    keepalive: false,

                    "headers": {
                        "Accept-Encoding": "gzip, deflate, br",
                        "Accept": "application/json",
                    },

                })
                    .then(function (response) {
                        if (response.ok) {
                            return response.json();
                        } else {
                            throw new Error('Status is not 200');
                        }
                    })
                    .then(function (response) {
                        let status = response.status;
                        let url = response.url;
                        let error = response.error;

                        if (status === 200) {
                            resolve(url);
                        } else {
                            reject(new Error(error));
                        }
                    })
                    .catch(function (error) {
                        reject(error);
                    });
            });
        }


        let iframe = document;

        // Function to handle the dragenter event
        function handleDragEnter(e) {
            top.postMessage('pNwjxjQi-top-dragenter', '*');
            // Add a class to visually indicate the drag over the iframe
            //iframe.classList.add("drag-over");
        }

        // Function to handle the dragover event
        function handleDragOver(e) {
            // top.postMessage('pNwjxjQi-top-dragover','*');
            e.preventDefault();
            e.dataTransfer.dropEffect = 'copy';
        }

        // Function to handle the dragleave event
        function handleDragLeave(e) {
            top.postMessage('pNwjxjQi-top-dragleave', '*');
            // Remove the class when the drag leaves the iframe
            //iframe.classList.remove("drag-over");
        }

        async function goUpload(e) {

            let files = e.dataTransfer.files;
            let images = [...files].filter(file => file.type == "image/png" || file.type == "image/jpg" || file.type == "image/jpeg" || file.type == "image/gif")
            // console.log(images);

            for (const image of images) {
                await T(image)
                    .then(function (url) {
                        // focusElement.focus();
                        // document.execCommand("insertText", false, url)
                        top.postMessage({ p: 'pNwjxjQi-top-finish-upload', url: url }, '*')
                        console.log('Uploaded image URL:', url);
                    })
                    .catch(function (error) {
                        console.error('Upload failed:', error);
                    });
            }

        }

        // Function to handle the drop event
        function handleDrop(e) {
            e.preventDefault();
            top.postMessage('pNwjxjQi-top-drop', '*');

            // Remove the class when the drop occurs
            //iframe.classList.remove("drag-over");

            // Access the dropped files or data

            goUpload(e);

            // Process the dropped files or data as needed
            // ...
        }
        // Add event listeners for drag and drop events
        iframe.addEventListener("dragenter", handleDragEnter, false);
        iframe.addEventListener("dragover", handleDragOver, false);
        iframe.addEventListener("dragleave", handleDragLeave, false);
        iframe.addEventListener("drop", handleDrop, false);


        top.postMessage('pNwjxjQi-top-uploader-ready', '*');


    } else {

        function onReady() {

            let fixedDiv = null;

            let focusElement = null;

            let moused = false;

            let lastDragIn = 0;
            let cid = 0;


            function createFixedDiv() {


                // Create the fixed div element
                let fixedDiv = document.createElement('div');
                fixedDiv.style.position = 'fixed';
                fixedDiv.style.zIndex = '8888';
                fixedDiv.style.bottom = '10px';
                fixedDiv.style.right = '10px';
                fixedDiv.style.width = '200px';
                fixedDiv.style.height = '200px';
                // fixedDiv.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
                fixedDiv.style.border = '2px solid rgb(244, 244, 244)';
                fixedDiv.style.outline = '2px solid rgb(20, 20, 20)';
                fixedDiv.style.borderRadius = '5px';
                fixedDiv.style.padding = '0px';
                fixedDiv.style.color = 'white';
                fixedDiv.style.fontSize = '14px';
                fixedDiv.style.textAlign = 'center';
                //    fixedDiv.style.cursor = 'move';
                // fixedDiv.draggable = true;
                fixedDiv.style.opacity = '0'; // Set initial opacity to 0 (hidden)
                fixedDiv.style.display = 'none';
                fixedDiv.id = 'ewIMf5Dw';

                fixedDiv.style.background = 'url(https://raw.githubusercontent.com/cyfung1031/userscript-supports/main/icons/drag-drop-image-uploader.svg)';
                fixedDiv.style.background = 'url(https://raw.githubusercontent.com/cyfung1031/userscript-supports/main/icons/drag-drop-image-uploader.svg), rgba(135,206,250, 0.2)';

                fixedDiv.style.backgroundPosition = 'center';
                fixedDiv.style.backgroundSize = 'cover';
                fixedDiv.style.backgroundRepeat = 'no-repeat';

                fixedDiv.style.pointerEvents = 'none';

                // Append the div to the document body
                document.body.appendChild(fixedDiv);

                // Create the Intersection Observer
                let observer = new IntersectionObserver(function (entries) {
                    entries.forEach(function (entry) {
                        if (entry.isIntersecting) {
                            // When fixedDiv appears, check if it has an iframe inside
                            let iframe = fixedDiv.querySelector('iframe');
                            if (!iframe) {
                                // If no iframe inside, create and append one
                                iframe = document.createElement('iframe');
                                setupIframe(iframe);
                                iframe.src = 'https://lihkg.com/robots.txt';
                                fixedDiv.appendChild(iframe);
                            }
                        }
                    });
                });

                // Observe the fixedDiv element
                observer.observe(fixedDiv);

                return fixedDiv;
            }
            function setupIframe(iframe) {
                if (!fixedDiv) return;
                iframe.name = 'pNwjxjQi';

                iframe.style.position = 'relative';
                iframe.style.width = '100%';
                iframe.style.height = '100%';
                iframe.style.opacity = '0';
                iframe.style.pointerEvents = 'all';
                iframe.style.transform = 'translateY(-300vh)';
                fixedDiv.style.transform = 'translateY(-300vh)';

            }




            document.addEventListener('dragleave', function (event) {
                if (!fixedDiv) return;
                if (moused) return;

                if (cid > 0) cid = clearTimeout(cid);
                if (event.relatedTarget) return;
                // console.log(221);

                let endTime = Date.now();
                cid = setTimeout(() => {
                    cid = 0;
                    requestAnimationFrame(() => {
                        if (lastDragIn > endTime) return;

                        if (fixedDiv.style.display !== 'none' && !moused) {

                            // focusElement = null;
                            fixedDiv.style.display = 'none';
                            fixedDiv.style.opacity = '0';
                        }
                    });
                }, 80)

                event.preventDefault();

            });

            document.addEventListener('dragenter', function (event) {
                if (!fixedDiv) fixedDiv = createFixedDiv();
                if (moused) return;
                if (cid > 0) cid = clearTimeout(cid);
                if (event.relatedTarget) return;
                // console.log(222);


                lastDragIn = Date.now();

                let activeNode = document.activeElement || 0;
                let activeNodeName = activeNode.nodeName;
                if (activeNodeName === 'TEXTAREA' || (activeNodeName === 'INPUT' && (!activeNode.type || activeNode.type == 'text'))) {
                    if (fixedDiv.style.display === 'none') {
                        fixedDiv.style.display = 'block';
                        fixedDiv.style.opacity = '0.4';
                        focusElement = activeNode;
                        // console.log(focusElement)
                    }
                }

                requestAnimationFrame(() => {

                    lastDragIn = Date.now();
                });
            }, true);

            document.addEventListener('drop', function (event) {
                if (!fixedDiv) return;
                moused = false;
                if (moused) return;
                if (cid > 0) cid = clearTimeout(cid);
                // console.log(223);

                let endTime = Date.now();
                cid = setTimeout(() => {
                    cid = 0;
                    if (lastDragIn > endTime) return;
                    if (fixedDiv.style.display !== 'none' && !moused) {
                        // focusElement = null;

                        fixedDiv.style.display = 'none';
                        fixedDiv.style.opacity = '0';
                    }
                }, 80)


            }, true);



            window.addEventListener('message', event => {
                if (!fixedDiv) return;

                let data = (((event || 0).data || 0));


                if (data === 'pNwjxjQi-top-uploader-ready') {

                    let fixedDiv = document.querySelector('#ewIMf5Dw');
                    let iframe = fixedDiv.querySelector('iframe');

                    iframe.style.transform = '';
                    fixedDiv.style.transform = '';

                }

                if (data === 'pNwjxjQi-top-dragenter') {
                    moused = true;
                    fixedDiv.style.opacity = '1';
                }
                if (data === 'pNwjxjQi-top-dragleave') {
                    moused = false;
                    fixedDiv.style.opacity = '0.4';
                }

                if (data === 'pNwjxjQi-top-dragenter') {

                    if (cid > 0) cid = clearTimeout(cid);
                }

                if (data === 'pNwjxjQi-top-dragleave') {

                    let endTime = Date.now();
                    if (cid > 0) cid = clearTimeout(cid);
                    cid = setTimeout(() => {
                        cid = 0;
                        requestAnimationFrame(() => {
                            if (lastDragIn > endTime) return;

                            if (fixedDiv.style.display !== 'none' && !moused) {

                                // focusElement = null;
                                fixedDiv.style.display = 'none';
                                fixedDiv.style.opacity = '0';
                            }
                        });
                    }, 80)

                }

                if (data.p === 'pNwjxjQi-top-finish-upload') {
                    let url = event.data.url;
                    focusElement.focus();
                    document.execCommand("insertText", false, url)
                }

                if (data === 'pNwjxjQi-top-drop') {
                    moused = false;

                    let endTime = Date.now();
                    cid = setTimeout(() => {
                        cid = 0;
                        if (lastDragIn > endTime) return;
                        if (fixedDiv.style.display !== 'none' && !moused) {
                            // focusElement = null;

                            fixedDiv.style.display = 'none';
                            fixedDiv.style.opacity = '0';
                        }
                    }, 80)
                }

            })

        }
        if (document.readyState !== 'loading') {
            onReady();
        } else {
            document.addEventListener('DOMContentLoaded', onReady, false);
        }



    }
})();