chimpanone / Sturdy dragable reply box

// ==UserScript==
// @name         Sturdy dragable reply box
// @version      0.0.3
// @description  Let's you drag a reply box
// @author       anone
// @match        https://sturdychan.help/*
// @grant        GM.getValue
// @grant        GM.setValue
// @grant        GM.deleteValue
// @grant        GM.registerMenuCommand
// @run-at       document-idle
// @license MIT
// ==/UserScript==
(function() {
    'use strict';
  const STORAGE_KEY = 'draggableDivPosition';
    const targetClasses = ['glass', 'editing', 'reply-form'];
    const postMine = ['glass', 'media', 'postMine'];
    const postMine2 = ['glass', 'postMine'];
    let currentForm = null;

    const observer = new MutationObserver((mutations) => {
        // Find the first matching form that hasn't been processed
        const form = document.querySelector('article.' + targetClasses.join('.'));
        if (form && form !== currentForm) {
            currentForm = form;
            setupDraggableForm(form);
           loadPosition(form);
        }

      const formMines = document.querySelectorAll('article.' + postMine.join('.'));
      const formMines2 = document.querySelectorAll('article.' + postMine2.join('.'));

      setTimeout(() => {
            formMines.forEach(formMine => {
                formMine.style.cssText = `
                    position: relative !important;
                    z-index: auto !important;
                    resize: none !important;
                    overflow: auto !important;
                    max-height: fit-content !important;
                    left: auto !important;
                    right: auto !important;
                `;

                formMine.style.removeProperty('top');
                formMine.style.removeProperty('bottom');
            });

            formMines2.forEach(formMine => {
                formMine.style.cssText = `
                    position: relative !important;
                    z-index: auto !important;
                    resize: none !important;
                    overflow: auto !important;
                    max-height: fit-content !important;
                    left: auto !important;
                    right: auto !important;
                `;

                formMine.style.removeProperty('top');
                formMine.style.removeProperty('bottom');
            });
        }, 5000); 
      
    });

    observer.observe(document.body, {
        childList: true,
        subtree: true,
        attributes: false,
        characterData: false
    });
  
   function savePosition(form) {
        const position = {
            left: form.offsetLeft,
            top: form.offsetTop,
            timestamp: Date.now()
        };
        
        try {
            localStorage.setItem(STORAGE_KEY, JSON.stringify(position));
            console.log('Position saved:', position);
        } catch (e) {
            console.warn('Failed to save position:', e);
        }
    }
  
    function loadPosition(form) {
        try {
            const saved = JSON.parse(localStorage.getItem(STORAGE_KEY));
            if (saved && isValidPosition(saved)) {
                form.style.left = `${saved.left}px`;
                form.style.top = `${saved.top}px`;
                console.log('Position loaded:', saved);
            }
        } catch (e) {
            console.warn('Failed to load position:', e);
        }
    }

    function isValidPosition(pos) {
        return Number.isInteger(pos.left) && 
               Number.isInteger(pos.top) &&
               pos.left >= 0 && 
               pos.top >= 0 &&
               pos.left < window.innerWidth &&
               pos.top < window.innerHeight;
    }

    function setupDraggableForm(form) {
        // Add essential styling
        form.style.position = 'fixed';
        form.style.zIndex = '9999';
        form.style.resize = 'both'; // Enable resizing
        form.style.overflow = 'auto';
				form.style.maxHeight = '25%';

        // Drag functionality
        let isDragging = false;
        let offset = { x: 0, y: 0 };
        const header = form.querySelector('header.spaced');

        // Preserve existing positioning if any
        const initialLeft = parseFloat(form.style.left) || 20;
        const initialTop = parseFloat(form.style.top) || 20;
        form.style.left = `${initialLeft}px`;
        form.style.top = `${initialTop}px`;

        // Header interaction
        header.style.cursor = 'move';
        header.addEventListener('mousedown', (e) => {
            // Ignore clicks on form elements
            if (e.target.closest('input, a, button, textarea')) return;
            
            isDragging = true;
            offset.x = e.clientX - form.offsetLeft;
            offset.y = e.clientY - form.offsetTop;
            form.style.zIndex = '10000';
            e.preventDefault();
        });

        // Mouse movement handler
        document.addEventListener('mousemove', (e) => {
            if (isDragging) {
                form.style.left = `${e.clientX - offset.x}px`;
                form.style.top = `${e.clientY - offset.y}px`;
               savePosition(form);
            }
        });

        // Cleanup on release
        document.addEventListener('mouseup', () => {
            isDragging = false;
            form.style.zIndex = '9999';
        });

        // Form controls protection
        form.querySelectorAll('input, textarea, button').forEach(el => {
            el.addEventListener('mousedown', (e) => e.stopPropagation());
        });

        // Window resize handler
        window.addEventListener('resize', () => {
            const rect = form.getBoundingClientRect();
            form.style.left = `${rect.left}px`;
            form.style.top = `${rect.top}px`;
        });
      
      	const postControls = form.querySelector('#post-controls');
        if (postControls) {
            // Apply required styles
            postControls.style.cssText = `
                position: absolute !important;
                bottom: 0px !important;
            `;
            
            // Additional control styling (optional)
            postControls.style.width = 'calc(100% - 20px)';
            postControls.style.padding = '10px 0';
        }
    }
})();