Greasy Fork

Greasy Fork is available in English.

英语阅读助手

使用在线翻译,获取单词解释,然后便于在网页上学习英语,而不是简单的使用翻译工具或插件整体翻译

目前为 2019-06-19 提交的版本,查看 最新版本

// ==UserScript==
// @name         英语阅读助手
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  使用在线翻译,获取单词解释,然后便于在网页上学习英语,而不是简单的使用翻译工具或插件整体翻译
// @author       lavaf
// @match        http://127.0.0.1:8848/TestyoudaoTranslate/Pages/testyouhou.html
// @match        http://www.51voa.com/*
// @grant        none
// @require https://cdn.jsdelivr.net/gh/emn178/js-sha256/build/sha256.min.js
// @require https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js
// ==/UserScript==

(function() {
    'use strict';
    var appKey = '';
    var Secret = ''; //注意:暴露appSecret,有被盗用造成损失的风险

    var from_l = 'en';
    var to = 'zh-CHS';
    var no_translate = ['a', 'an', 'of', 'some', 'the', 'than', 'would', 'this', 'to', 'rather', 'may', 'women', 'many',
                        'in', 'that', 'have', 'his', 'he', 'her', 'i', 'me', 'they', 'it', 'it\'s', 'myself', 'herself', 'for', 'on',
                        'has', 'first', 'second',
                        'am', 'is', 'are', 'were', 'did', 'do', 'does', 'be', 'us', 'was', 'will', 'any', 'other', 'from', 'and', 'him',
                        'no', 'not', 's', 'n',
                        'you', 'or', 'where', 'there', 'so', 'where', 'done', 'with', 'at', 'she'
                       ]
    //不需要翻译短语
    var no_idom = ['of']
    var textPanel; //全局的单词列表面板对象
    var result_count = 0; //已经获得的单词的数量
    var result_table = {} //全部已经获得的单词
    var deleted_table = {} // 已经删除不再显示的单词
    var speech_table = {} //存放音标和发音
    var loadJsonCallBack = {}
    var setting_item_name = ['show_delete_word_button', 'show_ph', 'show_ph_button']
    var setting = {
        'show_delete_word_button': false,
        'show_ph': false,
        'show_ph_button': false
    };
    var style = {
        controlpanel: {
            style: {},
            child: {
                'move-button': {},
                'start-button': {}
            }
        }
    }
    var adw = new addWin_fuzhengyin('50px', '100px');
    /*
			加载存储在local storage 中的数据
			*/
    if (localStorage) {
        var a = [
            'result-table',
            'speech-table',
            'deleted-table',
            'setting'
        ]
        var objects = [null, null, null, null]
        for (let var1 in a) {
            let current = a[var1]
            var result_temp = localStorage.getItem(current);
            if (result_temp != null) {

                objects[var1] = JSON.parse(result_temp);

                console.log("从localStorage中加载缓存" + current);
                adw.show("从localStorage中加载缓存" + current);
            }
        }
        if (objects[0] != null) result_table = objects[0]
        if (objects[1] != null) speech_table = objects[1]
        if (objects[2] != null) deleted_table = objects[2]
        if (objects[3] != null) setting = objects[3]

    }
    /*
			获取已经保存的单词数目
			*/
    for (let s in result_table) {
        result_count++;
    }
    var offestX, offestY;
    var movable = false;
    var button = getButton();
    setOnClick(button, 1);
    var panel = createControlPanel();
    panel.appendChild(button);
    document.body.appendChild(panel);

    var audio = document.createElement("audio");
    audio.src = "";
    document.body.appendChild(audio);
    var style_element=document.createElement('style');
    document.head.appendChild(style_element);
    style_element.innerText='#lavaf-start-get-word-button{color:red}'

    /**
			 * 创建控制面板
			 */
    function createControlPanel() {
        let div = document.createElement("div");
        div.style.id='lavaf-control-panel';
        div.style.position = "absolute";
        div.style.left = "10px";
        div.style.top = "100px";
        div.style.border = "#000000 solid 1px";
        div.style.padding = "10px";
        var move_button = document.createElement("button");
        move_button.id='lavaf-move-button';
        move_button.innerText = "◉";
        move_button.style.marginRight = "10px";
        move_button.onmousedown = function(e) {
            offestX = e.clientX - div.offsetLeft;
            offestY = e.clientY - div.offsetTop;
            movable = true;
        }
        appendMouseMoveEvents(div)

        var saved_count_panel = document.createElement("div");
        saved_count_panel.id='lavaf-show-saved-word-num';
        saved_count_panel.innerText = `保存的单词:${result_count}`
        div.appendChild(move_button);
        div.appendChild(saved_count_panel);
        //获取上次的选择
        var show_type_last_selection = "title";
        if (localStorage) {
            var save_show_type = localStorage.getItem("save-show-type");
            if (save_show_type != null) {
                show_type_last_selection = save_show_type;
            }
        }

        var selection_type_show = document.createElement("select");
        selection_type_show.id = "selection-type-show";
        var option1 = document.createElement("option");
        option1.id='lavaf-selection-type-option-item-1';
        option1.className='lavaf-selection-type-option-item';
        option1.value = "title";
        option1.innerText = "title";
        var option2 = document.createElement("option");
        option2.id='lavaf-selection-type-option-item-2';
        option2.className='lavaf-selection-type-option-item';
        option2.value = "fixed";
        option2.innerText = "fixed";
        if (show_type_last_selection === "title") {
            option1.selected = "selected";
        } else {
            option2.selected = "selected";
        }
        selection_type_show.appendChild(option1);
        selection_type_show.appendChild(option2);
        div.appendChild(selection_type_show);
        var mutil_container = document.createElement("div");
        mutil_container.id='lavaf-setting-multiple-select-container';
        var need_show_component = document.createElement("select");
        need_show_component.id='lavaf-setting-multiple-select';
        need_show_component.multiple='multiple';
        need_show_component.onchange=function(){
            let nodes=need_show_component.childNodes;
            if(nodes[3].selected){
                for (var i = 0; i < nodes.length-1; i++) {
                    nodes[i].selected=false;
                    nodes[i].blur();
                    for (let s of setting_item_name) {
                        setting[s] = false;
                    }
                }
            }else{
                for (var i = 0; i < nodes.length-1; i++) {
                    setting[setting_item_name[index]]=nodes[i].selected;
                }
            }
            localStorage.setItem('setting', JSON.stringify(setting))

        }
        var component_array = ["显示删除单词按钮", "显示音标", "显示发音按钮", "无"]
        for (let i in component_array) {
            let item=component_array[i]
            var option_show_delete_word = document.createElement("option");
            option_show_delete_word.id='lavaf-setting-multiple-select-option-'+item;
            option_show_delete_word.className='lavaf-setting-multiple-select-option-item';
            option_show_delete_word.value = item;
            option_show_delete_word.innerText = item
            need_show_component.appendChild(option_show_delete_word);
            if(item!=3){
                var item_selected = setting[setting_item_name[i]]
                option_show_delete_word.selected=item_selected;
                if (item_selected) {
                    option_show_delete_word.focus()
                } else {
                    // option_show_delete_word.blur
                }
            }
        }
        need_show_component.multiple = "multiple";
        mutil_container.appendChild(need_show_component);
        div.appendChild(mutil_container);
        //显示result-table 面板
        var result_table_panel = document.createElement("button");
        result_table_panel.id='lavaf-show-result-table-panel-button';
        result_table_panel.innerText = "显示全部单词";
        result_table_panel.onclick = function() {
            let r = "";
            for (let var1 in result_table) {
                if (deleted_table[var1] == null)
                    r += getWordListItem(var1);
            }
            showTextPanel(r);
        }
        div.appendChild(result_table_panel)
        div.appendChild(document.createElement('br'));

        var show_deleted_word = document.createElement("button");
        show_deleted_word.id='lavaf-show-deleted-word-button';
        show_deleted_word.innerText = "显示已删除单词";
        show_deleted_word.onclick = function() {
            let r = '';
            for (let var1 in deleted_table) {
                r += getWordListItem(var1);
                r += "<p>" + JSON.stringify(deleted_table[var1]) + "</p>";
            }
            showTextPanel(r);
        }

        div.appendChild(show_deleted_word);
        div.appendChild(document.createElement('br'));
        return div;
    }
    /**
			 * 有道提供
			 * @param {Object} input 要查询的单词
			 */
    function getInput(input) {
        if (input.length == 0) {
            return null;
        }
        var result;
        var len = input.length;
        if (len <= 20) {
            result = input;
        } else {
            var startStr = input.substring(0, 10);
            var endStr = input.substring(len - 10, len);
            result = startStr + len + endStr;
        }
        return result;
    }
    /**
			 * 为可移动的元素添加鼠标移动的事件
			 * @param {Object} div 需要操作的元素
			 */
    function appendMouseMoveEvents(div){
        div.onmousemove=function(e){
            if (movable) {
                var move_x = e.clientX - offestX;
                var move_y = e.clientY - offestY;
                div.style.top = move_y + "px";
                div.style.left = move_x + "px";
            }
        }
        div.onmouseup=function(){
            movable=false;
        }

    }
    /**
			 * 创建显示单词列表的面板
			 * @param {Object} str 要显示的html 内容
			 */
    function createTextPanel(str) {
        var div = document.createElement("div");
        var inner_button = document.createElement("button")
        inner_button.innerText = "◍";
        div.appendChild(inner_button)
        inner_button.onmousedown = function(e) {
            offestX = e.clientX - div.offsetLeft;
            offestY = e.clientY - div.offsetTop;
            movable = true;
        }
        appendMouseMoveEvents(div);
        var close_button = document.createElement("button");
        close_button.id='text-panel-close-button';
        close_button.innerText = "X";
        div.appendChild(close_button)
        close_button.onclick = function() {
            textPanel.style.display='none';
        }
        var inner_dix = document.createElement("div");
        div.style.position = "absolute";
        div.style.top = (100 + 10) + "px";
        div.style.left = (100 + 10) + "px";
        div.style.backgroundColor = "lightgray";
        div.style.color = "black";
        inner_dix.style.padding = "10px";
        inner_dix.innerHTML = str;
        div.appendChild(inner_dix)
        return div;
    }
    function addWin_fuzhengyin(left, top) {
        this.timeout;
        this.win;

        this.delay_move = function() {
            this.timeout = setTimeout(() => {
                document.body.removeChild(this.win);
                this.win = null;
            }, 2000)
        }
        this.show = function(msg) {
            if (this.win != null && this.win != undefined) {
                clearTimeout(this.timeout);
                this.win.innerText = msg;
                this.delay_move()
            } else {
                this.win = document.createElement('div');
                this.win.className = 'fuzhengyin-message';
                this.win.style.position = 'absolute';
                this.win.style.top = top || '100px';
                this.win.style.left = left || '100px';
                this.win.innerText = msg;
                this.win.style.backgroundColor = 'lightgreen';
                this.win.style.paddingLeft = '15px';
                this.win.style.paddingRight = '15px';
                this.win.style.paddingTop = '5px';
                this.win.style.paddingBottom = '5px';
                document.body.appendChild(this.win);
                this.delay_move()
            }
        }


    }
    /**
			 * 给p 添加title ,或者设置click事件
			 * @param {Object} word_table
			 * @param {Object} current_element
			 */
    function addTitleOrText(word_table, current_element) {
        let result = "";
        var current_selection_index = document.getElementById("selection-type-show").selectedIndex
        if (current_selection_index == 0) {
            for (let var1 in word_table) {
                if (result_table[word_table[var1]] != null)
                    result += word_table[var1] + ":" + result_table[word_table[var1]] + "\n";
            }
            current_element.title = result;
            localStorage.setItem("save-show-type", "title")
        } else {
            current_element.onclick = function() {
                showTextPanel(getResult(word_table));
            }
        }
    }
    function getResult(word_table){
        let result='';
        for (let var1 in word_table) { //显示文本面板
            let word_name = word_table[var1];
            if (result_table[word_name] != null) {
                // console.log(word_name+" "+deleted_table[word_name])
                if (deleted_table[word_name] == null){
                    result += getWordListItem(word_name);
                    // console.log(result)
                }

            }

        }
        // showTextPanel(result)
        return result
    }
    /**
			 * 显示单词列表框
			 * @param {Object} result
			 */
    function showTextPanel(result) {
        if (textPanel == null) {
            textPanel = createTextPanel(result);
            document.body.appendChild(textPanel);
            localStorage.setItem("save-show-type", "fixed")
        } else {
            //如果不为空就显示
            var currentTextPanelStatus=textPanel.style.display;
            textPanel.childNodes[textPanel.childNodes.length-1].innerHTML=result
            if(currentTextPanelStatus=='none'){
                textPanel.style.display='block';
            }

        }

    }
    /**
			 * 将单词添加到已删除列表
			 * @param {string} word_name 需要删除的单词
			 */
    function delete_word(word_name) {
        if (deleted_table[word_name] == null) {
            let t = new Date();
            deleted_table[word_name] = {
                'date': Date(),
                'm': t.getTime()
            }

        } else {
            delete deleted_table[word_name]
        }
        localStorage.setItem('deleted-table', JSON.stringify(deleted_table))
    }
    /**
			 * 获取单词列表详情
			 * @param {string} word_name 获取单词的解释
			 */
    function getWordListItem(word_name) {
        var ukph = speech_table[word_name]['uk-ph']
        var usph = speech_table[word_name]['us-ph']
        var setting_1 = setting[setting_item_name[1]]
        var setting_2 = setting[setting_item_name[2]]
        var setting_0 = setting[setting_item_name[0]]
        return '<div><span style=\"color:red;\">' + word_name + "</span>" +
            (setting_1 ? '<span>【' + speech_table[word_name]['ph'] + '】</span>' : '') +
            (setting_1 ? '<span>[' + (ukph == undefined ? 'x' : ukph) + ']</span>' : '') +
            (setting_2 ? '<button onclick=\'play(\"' + speech_table[word_name]['uk'] + '\")\'>o</button>' : '') +
            (setting_1 ? '<span>[' + (usph == undefined ? 'x' : usph) + ']</span>' : '') +
            (setting_2 ? '<button onclick=\'play(\"' + speech_table[word_name]['us'] + '\")\'>o</button>' : '') +
            ":" + result_table[word_name] +
            (setting_0 ? '<button onclick=\'delete_word(\"' + word_name + '\")\'>x</button>' : '') +
            "</div>";
    }
    /**
			 * 播放音频
			 * @param {Object} src 音频连接
			 */
    function play(src) {
        audio.src = src;
        audio.play()
    }
    /**
			 * 查看当前需要索引的单词是否都已经查找到,如果是那就开始显示
			 * @param {Object} word_table
			 * @param {Object} current_element
			 */
    function addTitleForP(word_table, current_element) {
        for (var m = 0; m < word_table.length; m++) {
            if (result_table[word_table[m]] == undefined) { //还有没完成的查询
                return;
            }
        }
        if (m == word_table.length) { //所有单词都完成了查询

            localStorage.setItem("result-table", JSON.stringify(result_table)); //保存数据
            localStorage.setItem("speech-table", JSON.stringify(speech_table));
            addTitleOrText(word_table, current_element);
            adw.show("单词全部获得解释,可以开始使用了")

        }
    }
    /**
			 * 为开始获取单词按钮设置事件
			 * @param {Object} button
			 * @param {Object} type
			 */
    function setOnClick(button, type) {
        button.onclick = function() {
            var p_array = document.getElementsByTagName("p");
            //遍历所有的 p 标签
            for (var i = 0; i < p_array.length; i++) {
                let current_element = p_array[i]; // 当前p 标签对象
                let p_text = p_array[i].innerText // 字符串 存储当前p 标签的内容
                let p_inner = p_text.split(/[\s,"']/); //数组 存储当前p 标签的每一个单词
                let word_table = [] //数组 存储需要索引的全部单词
                for (var j = 0; j < p_inner.length; j++) { //遍历每一个单词
                    let item_query = p_inner[j];
                    if (item_query.trim() === "" || item_query.trim() === "-") {
                        continue;
                    }
                    var last_char = item_query[item_query.length - 1];
                    if (last_char === ',' || last_char === '.' || last_char === '\'' || last_char === ')') {
                        item_query = item_query.substring(0, item_query.length - 1)
                    }
                    if (item_query.lastIndexOf("'s") >= 0) {
                        item_query = item_query.substring(0, item_query.length - 2)
                    }
                    for (var k = 0; k < no_translate.length; k++) {
                        if (no_translate[k] === item_query.toLowerCase()) {
                            break;
                        }
                    }

                    if (k == no_translate.length) { //需要翻译
                        word_table.push(item_query)
                        console.log("当前操作:" + item_query);
                        if (type == 1) {
                            var salt = (new Date).getTime(); //随机数
                            var curtime = Math.round(new Date().getTime() / 1000);
                            var str1 = appKey + getInput(item_query) + salt + curtime + Secret;
                            var sign = sha256(str1);
                            let current_index = j;
                            if (result_table[item_query] == null || result_table[item_query] == undefined) {
                                var s = document.createElement('script');
                                s.src = 'http://openapi.youdao.com/api?callback=loadJsonCallBack.callback' + current_index +
                                    `&q=${item_query}&appKey=${appKey}&salt=${salt}&from=${from_l}&to=${to}&curtime=${curtime}&sign=${sign}&signType=v3`;
                                document.body.appendChild(s);
                                loadJsonCallBack["callback" + current_index] = function(data) {
                                    console.log(data);
                                    // document.body.removeChild(s);
                                    console.log("联网获取到" + item_query + "的翻译");
                                    //完成查询时会把数据放到result-table中
                                    if (data.basic != null && data.basic.explains != null) {
                                        let explains = data.basic.explains;
                                        let r = `[${data.translation}],${JSON.stringify(explains)};\n`;
                                        result_table[item_query] = r;
                                        let current_speech = speech_table[item_query];
                                        if (current_speech == null) {
                                            speech_table[item_query] = {
                                                'uk': data.basic['uk-speech'],
                                                'us': data.basic['us-speech'],
                                                'us-ph': data.basic['us-phonetic'],
                                                'uk-ph': data.basic['uk-phonetic'],
                                                'ph': data.basic['phonetic']
                                            }

                                        }
                                    } else {
                                        if (data.translation != undefined) {
                                            let r = "[" + data.translation + "]\n";
                                            result_table[item_query] = r;
                                        } else {
                                            console.log("item_query:" + item_query);
                                            console.log(data);
                                        }
                                    }
                                    addTitleForP(word_table, current_element);
                                }
                            } else {
                                console.log("已获取" + item_query);
                                if (j == p_inner.length - 1) {
                                    addTitleForP(word_table, current_element);
                                }
                            } //查找调用完毕

                        } //查找调用类型配置完毕

                    } //翻译调用结束
                } //遍历单词结束
                //遍历完整个段落
            } //遍历段落结束
        } //监听函数设置完毕
    }
    /**
			 * 创建按钮
			 */
    function getButton() {
        var btn_start = document.createElement("button");
        btn_start.id='lavaf-start-get-word-button'
        btn_start.value = "开始";
        btn_start.type = "button";
        btn_start.innerText = "开始";
        return btn_start;
    }
})();