Greasy Fork is available in English.

Base64 智能划词编解码

Base64 智能划词编解码并复制到剪切板。

// ==UserScript==
// @name         Base64 智能划词编解码
// @description  Base64 智能划词编解码并复制到剪切板。
// @author       https://DUN.IM/
// @match        http://*/*
// @include      https://*/*
// @run-at       document-end
// @grant        GM_setClipboard
// @version 0.0.1.20200701093426
// @namespace https://greasyfork.org/users/662094
// ==/UserScript==

(function () {
    'use strict';

    var icon = document.createElement('div');
    var style = '' +
        'width:24px;' +
        'height:24px;' +
        'margin:4px!important;' +
        '';
    icon.innerHTML = '' +
        '<svg href="javascript:void(0)" style="' + style + '" "width="32" height="32" viewBox="0 0 1024 1024">' +
        '<path d="M709.8665356 500.26849902a203.11356548 203.11356548 0 0 0 102.40308912-157.41301317A233.58060062 233.58060062 0 0 0 565.14812046 116.89164421H180.07865289v790.45029216h434.15524617a220.03969619 220.03969619 0 0 0 228.50276078-214.11554998 209.88401731 209.88401731 0 0 0-132.87012424-192.95788737zM364.57347412 258.22483382h181.95590286a84.63065203 84.63065203 0 0 1 95.63263731 84.63065203 84.63065203 84.63065203 0 0 1-95.63263731 84.63065203H364.57347412v-169.26130406z m215.80816352 507.78391294H364.57347412v-169.26130405h215.80816352a84.63065203 84.63065203 0 0 1 93.09371738 84.63065203 84.63065203 84.63065203 0 0 1-93.09371738 84.63065202z" fill="#FFFFFF" p-id="4708"></path><path d="M709.8665356 500.26849902a203.11356548 203.11356548 0 0 0 102.40308912-157.41301317A233.58060062 233.58060062 0 0 0 565.14812046 116.89164421H180.07865289v790.45029216h434.15524617a220.03969619 220.03969619 0 0 0 228.50276078-214.11554998 209.88401731 209.88401731 0 0 0-132.87012424-192.95788737zM364.57347412 258.22483382h181.95590286a84.63065203 84.63065203 0 0 1 95.63263731 84.63065203 84.63065203 84.63065203 0 0 1-95.63263731 84.63065203H364.57347412v-169.26130406z m215.80816352 507.78391294H364.57347412v-169.26130405h215.80816352a84.63065203 84.63065203 0 0 1 93.09371738 84.63065203 84.63065203 84.63065203 0 0 1-93.09371738 84.63065202z" fill="#1296db" p-id="4709" data-spm-anchor-id="a313x.7781069.0.i13" class="selected"></path>' +
        '</svg>';
    icon.setAttribute('style', '' +
                      'width:32px!important;' +
                      'height:32px!important;' +
                      'display:none!important;' +
                      'background:#fff!important;' +
                      'border-radius:16px!important;' +
                      'box-shadow:4px 4px 8px #888!important;' +
                      'position:absolute!important;' +
                      'z-index:2147483647!important;' +
                      '');

    // 添加解析图标到 DOM
    document.documentElement.appendChild(icon);
    // 鼠标事件:防止选中的文本消失
    document.addEventListener('mousedown', function (e) {
        if (e.target == icon || (e.target.parentNode && e.target.parentNode == icon) || (e.target.parentNode.parentNode && e.target.parentNode.parentNode == icon)) {// 点击了解析图标
            e.preventDefault();
        }
    });
    // 选中变化事件:当点击已经选中的文本的时候,隐藏解析图标和解析面板(此时浏览器动作是:选中的文本已经取消选中了)
    document.addEventListener("selectionchange", function () {
        if (!window.getSelection().toString().trim()) {
            icon.style.display = 'none';
            resultlayer.containerDestroy();
        }
    });
    // 鼠标事件:防止选中的文本消失;显示、隐藏解析图标
    document.addEventListener('mouseup', function (e) {
        if (e.target == icon || (e.target.parentNode && e.target.parentNode == icon) || (e.target.parentNode.parentNode && e.target.parentNode.parentNode == icon)) {// 点击了解析图标
            e.preventDefault();
            return;
        }
        for (var i = 0; i < resultlayer.rendered.length; i++) {// 点击了解析内容面板
            if (e.target == resultlayer.rendered[i]) {
                return;// 不再创建解析图标
            }
        }

        var text = window.getSelection().toString().trim();
        if (text && icon.style.display == 'none') {
            icon.style.top = e.pageY - 24 + 'px';
            icon.style.left = e.pageX + 'px';
            icon.style.display = 'block';
        } else if (!text) {
            icon.style.display = 'none';
            resultlayer.containerDestroy();// 销毁解析内容面板
        }
    });
    // 解析图标点击事件
    icon.addEventListener('click', function (e) {
        var text = window.getSelection().toString().trim();
        if (text) {
            icon.style.display = 'none';
            resultlayer.containerDestroy();// 销毁解析内容面板
            // 新建解析内容面板
            var container = resultlayer.container();
            container.style.top = e.pageY + 'px';
            if (e.pageX + 350 <= document.body.clientWidth) { // container 面板 css 最大宽度为 250px
                container.style.left = e.pageX + 'px';
            } else {
                container.style.left = document.body.clientWidth - 350 + 'px';
            }
            document.body.appendChild(container);
            resultlayer.rendered.push(container);
            if (isBase64(text)) {
                var result = Base64.decode(text);
            } else {
                 result = Base64.encode(text);
            }
            displaycontainer(result, container);
            GM_setClipboard(result);
        }
    });

    function displaycontainer(text, element) {
        element.innerHTML = text;
        element.style.display = 'block';// 显示结果
    }

    // 解析面板
    var resultlayer = {
        // 存放已经生成的翻译内容面板(销毁的时候用)
        rendered: [],
        // 销毁已经生成的翻译内容面板
        containerDestroy: function () {
            for (var i = this.rendered.length - 1; i >= 0; i--) {
                if (this.rendered[i] && this.rendered[i].parentNode) {
                    this.rendered[i].parentNode.removeChild(this.rendered[i]);
                }
            }
        },
        // 生成翻译结果面板 DOM (此时还未添加到页面)
        container: function () {
            var div = document.createElement('div');
            div.setAttribute('style', '' +
                             'display:none!important;' +
                             'position:absolute!important;' +
                             'font-size:13px!important;' +
                             'overflow:auto!important;' +
                             'background:#fff!important;' +
                             'font-family:sans-serif,Arial!important;' +
                             'font-weight:normal!important;' +
                             'text-align:left!important;' +
                             'color:#000!important;' +
                             'padding:0.5em 1em!important;' +
                             'line-height:1.5em!important;' +
                             'border-radius:5px!important;' +
                             'border:1px solid #ccc!important;' +
                             'box-shadow:4px 4px 8px #888!important;' +
                             'max-width:350px!important;' +
                             'max-height:216px!important;' +
                             'z-index:2147483647!important;' +
                             '');
            return div;
        }
    };// 解析面板 resultlayer 结束

    function isBase64(str) {
        str = str.replace(/[\r\n\s]/g, '');
        if (str ==='' || str.trim() ===''){ return false; }
        try {
            return Base64.encode(Base64.decode(str)) == str;
        } catch (err) {
            return false;
        }
    }


    // Base64 encode / decode
    // http://www.webtoolkit.info
    var Base64 = {
        // private property
        _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="

        // public method for encoding
        , encode: function (input)
        {
            var output = "";
            var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
            var i = 0;

            input = Base64._utf8_encode(input);

            while (i < input.length)
            {
                chr1 = input.charCodeAt(i++);
                chr2 = input.charCodeAt(i++);
                chr3 = input.charCodeAt(i++);

                enc1 = chr1 >> 2;
                enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
                enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
                enc4 = chr3 & 63;

                if (isNaN(chr2))
                {
                    enc3 = enc4 = 64;
                }
                else if (isNaN(chr3))
                {
                    enc4 = 64;
                }

                output = output +
                    this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
                    this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
            } // Whend

            return output;
        } // End Function encode


        // public method for decoding
        ,decode: function (input)
        {
            var output = "";
            var chr1, chr2, chr3;
            var enc1, enc2, enc3, enc4;
            var i = 0;

            input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
            while (i < input.length)
            {
                enc1 = this._keyStr.indexOf(input.charAt(i++));
                enc2 = this._keyStr.indexOf(input.charAt(i++));
                enc3 = this._keyStr.indexOf(input.charAt(i++));
                enc4 = this._keyStr.indexOf(input.charAt(i++));

                chr1 = (enc1 << 2) | (enc2 >> 4);
                chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
                chr3 = ((enc3 & 3) << 6) | enc4;

                output = output + String.fromCharCode(chr1);

                if (enc3 != 64)
                {
                    output = output + String.fromCharCode(chr2);
                }

                if (enc4 != 64)
                {
                    output = output + String.fromCharCode(chr3);
                }

            } // Whend

            output = Base64._utf8_decode(output);

            return output;
        } // End Function decode


        // private method for UTF-8 encoding
        ,_utf8_encode: function (string)
        {
            var utftext = "";
            string = string.replace(/\r\n/g, "\n");

            for (var n = 0; n < string.length; n++)
            {
                var c = string.charCodeAt(n);

                if (c < 128)
                {
                    utftext += String.fromCharCode(c);
                }
                else if ((c > 127) && (c < 2048))
                {
                    utftext += String.fromCharCode((c >> 6) | 192);
                    utftext += String.fromCharCode((c & 63) | 128);
                }
                else
                {
                    utftext += String.fromCharCode((c >> 12) | 224);
                    utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                    utftext += String.fromCharCode((c & 63) | 128);
                }

            } // Next n

            return utftext;
        } // End Function _utf8_encode

        // private method for UTF-8 decoding
        ,_utf8_decode: function (utftext)
        {
            var string = "";
            var i = 0;
            var c, c1, c2, c3;
            c = c1 = c2 = 0;

            while (i < utftext.length)
            {
                c = utftext.charCodeAt(i);

                if (c < 128)
                {
                    string += String.fromCharCode(c);
                    i++;
                }
                else if ((c > 191) && (c < 224))
                {
                    c2 = utftext.charCodeAt(i + 1);
                    string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                    i += 2;
                }
                else
                {
                    c2 = utftext.charCodeAt(i + 1);
                    c3 = utftext.charCodeAt(i + 2);
                    string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                    i += 3;
                }

            } // Whend

            return string;
        } // End Function _utf8_decode
    };

})();