Text Converter

Convert selected text to HTML Element

// ==UserScript==
// @name         Text Converter
// @namespace    https://github.com/invobzvr
// @version      0.4
// @description  Convert selected text to HTML Element
// @author       invobzvr
// @match        *://*/*
// @grant        GM_addStyle
// @homepageURL  https://github.com/invobzvr/invotoys.js/tree/main/text_converter
// @supportURL   https://github.com/invobzvr/invotoys.js/issues
// @license      GPL-3.0
// ==/UserScript==

(function () {
    function pointOf(evt) {
        let pageX, pageY;
        isMobile && (evt = evt.changedTouches[0]);
        pageX = evt.pageX;
        pageY = evt.pageY + 10;
        return { pageX, pageY };
    }

    const isMobile = navigator.userAgent.includes('Mobile'),
        EVTS = [DOWN_EVT, UP_EVT] = isMobile ? ['touchstart', 'touchend'] : ['mousedown', 'mouseup'],
        SLCN = window.getSelection(),
        EL_TYPE = {
            Image: 'img',
            Video: 'video',
            Link: 'a',
        };
    let ctnr, rng, cr, text;
    addEventListener(DOWN_EVT, () => ctnr && (ctnr = ctnr.remove()));
    addEventListener(UP_EVT, evt => {
        if (!SLCN.rangeCount || rng === (cr = SLCN.getRangeAt(0)) || !(text = (rng = cr).toString())) {
            return;
        }
        const { pageX, pageY } = pointOf(evt);
        ctnr = document.body.insertAdjacentElement('beforeend', document.createElement('div'));
        ctnr.className = 'tc_ctnr';
        ctnr.style = `top:${pageY}px;left:${pageX}px`;
        EVTS.forEach(name => ctnr.addEventListener(name, evt => evt.stopPropagation()));
        ctnr.addEventListener('click', evt => {
            let el = document.createElement(EL_TYPE[evt.target.innerText]);
            switch (evt.target.innerText) {
                case 'Image':
                case 'Video':
                    el.src = text;
                    break;
                case 'Link':
                    el.target = '_blank';
                    el.href = text;
                    break;
            }
            rng.surroundContents(el);
            rng.collapse();
            ctnr && (ctnr = ctnr.remove());
        });
        ctnr.innerHTML = `<div>Image</div><div>Video</div><div>Link</div>`;
    });

    GM_addStyle(`.tc_ctnr {
    background: #fff;
    border-radius: 5px;
    box-shadow: 0 0 5px #0009;
    color: #000;
    font-size: 12px;
    line-height: initial;
    overflow: hidden;
    position: absolute;
    user-select: none;
    z-index: 999;
}
.tc_ctnr>div {
    padding: 5px 7px;
    transition: .2s;
}
.tc_ctnr>div:hover {
    background: #0002;
}
.tc_ctnr>div:not(:last-child) {
    border-bottom: 1px solid #0003;
}`);
})();