Skip to main content

Handy Tool For Web

Submitted by Prateek Kher on

Here is a Handy Tool for Edge / Chrome. It removes readonly, disabled fields toggles contenteditable Attribute on body tag and can import and export form data for quick form autofill.

 

// ==UserScript==
// @name         Universal Handy Web Tools Panel
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Gifts handy buttons: remove readonly/disabled, toggle contenteditable, export/import forms as JSON!
// @author       You
// @match        *://*/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // ---- CSS for floating tools ----
    const css = `
    #hwt-btn {
        position: fixed;
        bottom: 20px; left: 20px;
        z-index: 99999; background: #0b6dff;
        color: #fff; border: none; border-radius: 10px;
        font-size: 18px; padding: 10px 18px;
        cursor: pointer; box-shadow: 0 5px 20px #0003;
        transition: background .2s;
    }
    #hwt-btn:hover { background: #094aaf; }
    #hwt-panel {
        position: fixed; bottom: 80px; left: -500px;
        width: 220px; background: #f9f9fd;
        border: 1px solid #dde; border-radius: 10px;
        box-shadow: 0 8px 24px #0005;
        padding: 16px 13px; z-index: 99998;
        display: flex; flex-direction: column; gap: 14px;
        transition: left .36s cubic-bezier(.67,1.4,.5,1);
    }
    #hwt-panel.open { left: 20px; }
    .hwt-tool-btn {
        background: #16a75c;
        color: #fff; border: none;
        border-radius: 6px; font-size: 15px;
        padding: 7px 10px;
        cursor: pointer; transition: background .15s;
    }
    .hwt-tool-btn:hover { background: #0e7a40; }
    #hwt-export-link {
        color: #007aaa; text-decoration: underline;
        font-size: 13px; margin-top: 2px; cursor: pointer;
        background: none !important; border: none !important; padding: 0;
    }
    #hwt-file-input { display: none; }
    /* Hide on print */
    @media print {
        #hwt-btn, #hwt-panel { display:none!important; visibility:hidden!important;}
    }
    `;
    const style = document.createElement('style');
    style.textContent = css;
    document.head.appendChild(style);

    // ---- Main Button ----
    const mainBtn = document.createElement('button');
    mainBtn.id = 'hwt-btn'
    mainBtn.textContent = '🛠️ Tools';
    document.body.appendChild(mainBtn);

    // ---- Tools panel ----
    const panel = document.createElement('div');
    panel.id = 'hwt-panel';
    document.body.appendChild(panel);

    // ---- In-page non-blocking alert ----
    function toast(msg) {
        const div = document.createElement('div');
        div.style.cssText = 'position:fixed;top:48%;left:50%;transform:translate(-50%,-50%);background:#222;color:#fff;padding:15px 32px;border-radius:9px;box-shadow:0 7px 17px #0003;z-index:200000;font-size:18px;opacity:0;transition:opacity .2s;';
        div.textContent = msg;
        document.body.appendChild(div);
        setTimeout(()=>{div.style.opacity='1'},10);
        setTimeout(()=>{
            div.style.opacity='0';
            div.addEventListener('transitionend', ()=>div.remove());
        },1800);
    }

    // ---- Tool actions ----
    function removeReadonly() {
        let n = 0;
        document.querySelectorAll('input[readonly],textarea[readonly]').forEach(el=>{
            el.removeAttribute('readonly'); n++;
        });
        toast(`Removed readonly from ${n} fields.`);
    }

    function removeDisabled() {
        let n = 0;
        document.querySelectorAll('[disabled]').forEach(el=>{
            el.removeAttribute('disabled'); n++;
        });
        toast(`Removed disabled from ${n} elements.`);
    }

    let bodyEditable = false;
    function toggleContentEditable() {
        bodyEditable = !bodyEditable;
        document.body.contentEditable = bodyEditable ? 'true' : 'false';
        document.designMode = bodyEditable ? 'on' : 'off';
        toast(bodyEditable ? 'Page is editable.' : 'Page edit mode OFF.');
    }

    function getInputData() {
        const obj = {};
        document.querySelectorAll('input[name],textarea[name],select[name]').forEach(el => {
            const name = el.name;
            // Handle checkboxes/radios
            if (el.type === 'checkbox') {
                obj[name] = el.checked;
            } else if (el.type === 'radio') {
                if (el.checked) obj[name] = el.value;
            } else {
                obj[name] = el.value;
            }
        });
        // Fallback to ID for those without name
        document.querySelectorAll('input[id]:not([name]),textarea[id]:not([name]),select[id]:not([name])').forEach(el=>{
            if(!(el.id in obj)) {
                if(el.type === 'checkbox') {
                    obj[el.id] = el.checked;
                } else if(el.type==='radio') {
                    if(el.checked) obj[el.id]=el.value;
                } else {
                    obj[el.id] = el.value;
                }
            }
        })
        return obj;
    }

    // ---- Export action ----
    function exportInputs() {
        const data = getInputData();
        const blob = new Blob([JSON.stringify(data, null, 2)], {type: 'application/json'});
        const url = URL.createObjectURL(blob);

        // Download simulation
        const a = document.createElement('a');
        a.href = url;
        a.download = 'form_data.json';
        document.body.appendChild(a);
        a.click();
        setTimeout(()=>{URL.revokeObjectURL(url);a.remove();}, 300);
        toast('Exported input fields as JSON!');
    }

    // ---- Import & autofill ----
    let importInput = document.createElement('input');
    importInput.type = 'file';
    importInput.accept = '.json,application/json';
    importInput.id = 'hwt-file-input';
    document.body.append(importInput);

    function fillImported(json) {
        let n = 0;
        for (const [k,v] of Object.entries(json)) {
            // try name first for all types of fields, fallback to id
            let els = document.querySelectorAll(`[name='${CSS.escape(k)}'],#${CSS.escape(k)}`);
            if (!els.length) continue;
            els.forEach(el=>{
                if (el.type === 'checkbox') {
                    el.checked = !!v;
                    n++;
                } else if (el.type === 'radio') {
                    if (el.value == v) { el.checked = true; n++; }
                } else if (el.tagName === 'SELECT' || el.tagName === 'INPUT' || el.tagName === 'TEXTAREA') {
                    el.value = v;
                    n++;
                }
            });
        }
        toast(n ? `Filled ${n} field${n===1?'':'s'}.` : 'No matching fields found in form.');
    }

    importInput.addEventListener('change', async e => {
        const file = importInput.files[0];
        if (!file) return;
        try {
            const txt = await file.text();
            const json = JSON.parse(txt);
            fillImported(json);
        } catch {
            toast("Invalid JSON file.");
        }
        importInput.value = "";
    });

    // ---- UI Buttons ----
    const btnRemoveRo = document.createElement('button');
    btnRemoveRo.className = 'hwt-tool-btn';
    btnRemoveRo.textContent = 'Remove All Readonly';
    btnRemoveRo.onclick = removeReadonly;

    const btnRemoveDis = document.createElement('button');
    btnRemoveDis.className = 'hwt-tool-btn';
    btnRemoveDis.textContent = 'Remove All Disabled';
    btnRemoveDis.onclick = removeDisabled;

    const btnToggleEditable = document.createElement('button');
    btnToggleEditable.className = 'hwt-tool-btn';
    btnToggleEditable.textContent = 'Toggle Edit Page';
    btnToggleEditable.onclick = toggleContentEditable;

    const btnExport = document.createElement('button');
    btnExport.className = 'hwt-tool-btn';
    btnExport.textContent = 'Export Inputs as JSON';
    btnExport.onclick = exportInputs;

    const btnImport = document.createElement('button');
    btnImport.className = 'hwt-tool-btn';
    btnImport.textContent = 'Import & Fill Inputs';
    btnImport.onclick = ()=>importInput.click();

    panel.appendChild(btnRemoveRo);
    panel.appendChild(btnRemoveDis);
    panel.appendChild(btnToggleEditable);
    panel.appendChild(btnExport);
    panel.appendChild(btnImport);

    // ---- Panel Slide Toggle ----
    mainBtn.onclick = ()=>{ panel.classList.toggle('open') };

    // ---- Click-away to close panel ----
    document.addEventListener('mousedown', e=>{
        if (
            !panel.contains(e.target) &&
            !mainBtn.contains(e.target) &&
            panel.classList.contains('open')
        ) { panel.classList.remove('open'); }
    });

    // ---- Hide tools panel on print (JS layer for extra safety) ----
    window.addEventListener('beforeprint', ()=>{
        mainBtn.style.display='none';
        panel.style.display='none';
    });
    window.addEventListener('afterprint', ()=>{
        mainBtn.style.display='';
        panel.style.display='';
    });
})();