JSON paste on textarea

Paste JSON on textarea

// ==UserScript==
// @name         JSON paste on textarea
// @version      0.6
// @description  Paste JSON on textarea
// @match        https://*/*
// @grant        none
// @namespace https://greasyfork.org/users/371179
// ==/UserScript==
(function() {
    'use strict';

    /*

    -- Example --
    https://jsonformatter.curiousconcept.com/
    "{\"a\":1,\"b\":2,\"c\":3,\"d\":\"A\",\"e\":\"B\",\"f\":\"C\"}"

    */

    function getClipText(evt) {

        var text;
        var clp = (evt.originalEvent || evt).clipboardData;
        if (clp === undefined || clp === null) {
            text = window.clipboardData.getData("text") || null;
        } else {
            text = clp.getData('text/plain') || null;
        }
        return text;

    }

    //  =========================================================================================
    // https://stackoverflow.com/questions/7464282/javascript-scroll-to-selection-after-using-textarea-setselectionrange-in-chrome

    function setSelectionRange(textarea, selectionStart, selectionEnd) {
        // First scroll selection region to view
        const fullText = textarea.value;
        textarea.value = fullText.substring(0, selectionEnd);
        // For some unknown reason, you must store the scollHeight to a variable
        // before setting the textarea value. Otherwise it won't work for long strings
        const scrollHeight = textarea.scrollHeight
        textarea.value = fullText;
        let scrollTop = scrollHeight;
        const textareaHeight = textarea.clientHeight;
        if (scrollTop > textareaHeight) {
            // scroll selection to center of textarea
            scrollTop -= textareaHeight / 2;
        } else {
            scrollTop = 0;
        }
        textarea.scrollTop = scrollTop;

        // Continue to set selection range
        textarea.setSelectionRange(selectionStart, selectionEnd);
    }
    //  =========================================================================================


    if (document.queryCommandSupported("insertText")) {

        var object = {

            callback: function(str) {

                var targetElm = this.targetElm;
                var clipText = this.clipText;

                var newClipText = typeof str == 'string' ? str : clipText;
                if (newClipText != "") {


                    var oldText = targetElm.value
                    document.execCommand("insertText", false, newClipText);

                    if ('selectionStart' in targetElm) {
                        var afterChange = () => {
                            var newText = targetElm.value;
                            if (oldText == newText) return window.requestAnimationFrame(afterChange);
                            setSelectionRange(targetElm, targetElm.selectionStart, targetElm.selectionEnd);
                        };

                        window.requestAnimationFrame(afterChange);

                    }
                }

            }
        };

        var JF_safeObjects=[];

        var makeJFunction = (() => {
            var a = document.createElement('iframe');
            a.style.position = 'absolute';
            a.style.left = '-99px';
            a.style.top = '-99px';
            a.src = "about:blank"; //userscript can access "about:blank"
            a.width = "1";
            a.height = "1";
            document.documentElement.appendChild(a)
            // it is assumed that the "contentWindow" is immediately available after appendChild
            var JFunction;
            try {
                JFunction = (a.contentWindow || window).Function;
            } catch (e) {
                JFunction = window.Function
            }

            document.documentElement.removeChild(a)

            var res2 = null;
            try {
                var res = new JFunction('return Object.keys(window);')(); // avoid no access to JFunction
                res2 = [...res]; // transfer the js array object to the current framework
            } catch (e) {}

            if (res2 && 'forEach' in res2) {
                JF_safeObjects=res2;
            }else{
                JFunction = window.Function;
                JF_safeObjects=[];
            }

            return JFunction
        });


        var JFunction = null;
        document.addEventListener('paste', function(evt) {

            var clipText = getClipText(evt)
            if (clipText === null || typeof clipText != 'string') return;

            var targetElm = evt.target;

            if (!targetElm) return;

            switch (targetElm.tagName) {
                case 'TEXTAREA':
                    break;
                default:
                    return;
            }

            var testingStr=clipText.replace(/[0-9]+/g,'0')
            testingStr=testingStr.replace(/[a-zA-Z\u4E00-\u9FFF]+/g,'z')
            if (/[\[\{][\s\S]*[\]\}]/.test(testingStr)&&/[\'\"\`][\s\S]*[\'\"\`]/.test(testingStr)){}else{ return;}

            var testP = testingStr.replace(/[0z\/\%\-\+\_\.\;\$\#]+/g, '').trim();
            var testR = /^[\x21-\x2F\x3A-\x40\x5B-\x60\x7B-\x7E]+$/
            if (!testP) {
                return;
            }
            if (!testR.test(testP)) return;

            object.targetElm = targetElm;
            object.clipText = clipText;

            // JS-safe Function
            JFunction = JFunction || makeJFunction();

            //window.JF = JFunction



            var res = null;
            try {
                res = new JFunction(...JF_safeObjects,'return (' + clipText + ');')(); //backbracket to avoid return newline -> undefined
            } catch (e) {}

            //console.log(res)

            if (typeof res == 'string') {
                console.log('userscript - there is a text convertion to your pasted content');
                evt.preventDefault();
                object.callback(res);
            }


        });
    }

    // Your code here...
})();