minerva-online assistant

此脚本能更方便使用minerva-online平台,可在顶端菜单栏右下角的按钮处设置功能开关,并查看功能详情

当前为 2021-10-29 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         minerva-online assistant
// @namespace    https://space.bilibili.com/17846288
// @version      2.4.5
// @description  此脚本能更方便使用minerva-online平台,可在顶端菜单栏右下角的按钮处设置功能开关,并查看功能详情
// @author       inoki
// @match        https://www.minerva-online.com/*
// @require      https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_xmlhttpRequest
// @noframes
// ==/UserScript==

/*jshint esversion: 9*/

(()=>{
    'use strict';

    const $=window.$;
    const SET=[
        {
            'id':0,
            'name':'置顶置底',
            'func':()=>{GOTOPBOTTOM();},
            'unfunc':()=>{unGOTOPBOTTOM();},
            'detail':
            `在平台域名所有可滚动页面生效,页面右下方添加置顶置底按钮<br>
            按钮会根据页面滚动方向自动切换置顶和置底,按钮样式可在代码中自定义中修改`,
            'switch':1,
        },
        {
            'id':1,
            'name':'菜单遮罩',
            'func':()=>{COVERMENU();},
            'unfunc':()=>{unCOVERMENU();},
            'detail':
            `在有顶端菜单栏的页面生效<br>
            让菜单栏需要点击一次后才可展开,防止鼠标经过时误触 (默认关闭)`,
            'switch':0,
        },
        {
            'id':2,
            'name':'附件下载',
            'func':()=>{DOWNLOADFILE();},
            'unfunc':()=>{unDOWNLOADFILE();},
            'detail':
            `在问卷管理页面生效,每份报告前添加↓按钮<br>
            点击↓加载附件列表,点击√下载全部附件,点击附件名下载单个附件,鼠标悬停可预览图片`,
            'switch':1,
        },
        {
            'id':3,
            'name':'扣分标记',
            'func':()=>{MARKQUESTION();},
            'unfunc':()=>{unMARKQUESTION();},
            'detail':
            `在单店报告页面生效<br>
            将题目中勾选扣分和n/a项标色,选项更改后需保存报告才会刷新标记,方便快速检查相关题评论<br>
            可在简介上方分别设置扣分(默认为红)和N/A(默认为绿)的标记颜色,点击√保存更改`,
            'switch':1,
        },
        {
            'id':4,
            'name':'评论编辑',
            'func':()=>{COMMENTEDIT();},
            'unfunc':()=>{unCOMMENTEDIT();},
            'detail':
            `在单店报告页面生效,右下方按钮展开操作界面<br>
            使用前请注意阅读操作界面最上方的【点击获取提示】<br>
            输入匹配内容(支持正则)会即时显示匹配的评论框数量并标灰,点击一键替换可批量修改所有评论框内容<br>
            点击首字母大写可智能将所有句首字母变为大写,并标灰发生过修改的评论框,只对英文生效<br>
            点击评论翻译会调用百度翻译(由于需要跨域请求,弹出提示后选“总是允许”),在每个评论框下方输出目标语言翻译,点击↑可将下方内容添加至评论框`,
            'switch':1,
        },
        {
            'id':5,
            'name':'验证输出',
            'func':()=>{VERIFYEXPORT();},
            'unfunc':()=>{unVERIFYEXPORT();},
            'detail':
            `在问卷管理页面生效,表头上方添加按钮<br>
            点击按钮弹出确认提示,确认后会验证输出当前页面勾选的所有报告,成功后会在每份报告下方小窗口显示绿色保存成功提示<br>
            (电脑配置较低时一次输出太多份可能导致页面卡死,请根据浏览器最多同时能开几个报告页面量力而行)`,
            'switch':1,
        },
    ];


    /*在顶端菜单栏添加MOassist设置按钮*/
    const menu=$('div#menu');
    if(menu.length){
        menu.find('ul.tools').append(`
        <li class="MOassist">
            <a class="toolsLink">
                <div class="iconTools" style="background: url('/images/icons/menu/x16/tools-settings.png')"></div>
                <ul class="textArea" style="visibility:visible; display:none">
                    <li>MO助手设置</li>
                </ul>
                <ul id="MOoption" class="innerItemFirst" style="z-index: 11; display:none; top:25px; right:0px"></ul>
            </a>
        </li>
        `);
        menu.find('li.MOassist').on('click',function(){
            MOListSwitch(this);
        }).find('ul#MOoption').on('click',e=>{
            e.stopPropagation();//让之后添加的功能列表不继承click事件
        });
        //导入所有功能列表并显示开关状态
        for(let i in SET){
            menu.find('ul#MOoption').append(`
            <li id="MOoptions" class="MOassist" style="width:100%">
                <div class="menuItemText" style="color:#4C5057">${SET[i].name}</div>
                <input type=checkbox id=${SET[i].id} class=menuIconSmall></input>
                <ul class="textArea" style="visibility:visible; display: none; margin-top:0px; right:120px">
                    <li style="padding:0px 5px !important">${SET[i].detail}</li>
                </ul>
            </li>
            `);
            //运行开启状态的功能并打勾
            if(GM_getValue(SET[i].name,SET[i].switch)){
                SET[i].func();
                menu.find('input#'+SET[i].id).attr('checked',true);
            }
        }
        //根据是否选中即时启用或卸载功能并记录开关状态
        menu.find('li#MOoptions').on('click',function(){
            const checkbox=$(this).find('input');
            const id=$(checkbox).attr('id');
            if($(checkbox).attr('checked')){
                SET[id].unfunc();
                $(checkbox).attr('checked',false);
                GM_setValue(SET[id].name,0);
            }
            else{
                SET[id].func();
                $(checkbox).attr("checked",true);
                GM_setValue(SET[id].name,1);
            }
        }).children('ul.textArea').on('click',e=>{
            e.stopPropagation();
        });
        //鼠标聚焦时显示详情 【https://www.minerva-online.com/portal/menu/js/v2/menuRender.js?version=21-08 createToolOption : 】
        menu.find('li.MOassist').hover(function(){
            $(this).find('ul:first').stop().show(200);
        },function(){
            $(this).find('ul:first').stop().hide(200);
        });
        setMarkQuestionColor(menu);
    }
    else{
        for(let i in SET) if(GM_getValue(SET[i].name,SET[i].switch)) SET[i].func();//没有menu也执行开启的功能
    }

    //功能列表开关
    function MOListSwitch(self){
        const on=$(self).find('ul#MOoption').css('display');
        if(on==='none'){
            $(self).find('ul#MOoption').stop().slideDown(200);
        }
        else{
            $(self).find('ul#MOoption').stop().slideUp(200);
        }
    }

    //添加扣分标记颜色设置界面
    function setMarkQuestionColor(menu){
        $(menu).find('input#3.menuIconSmall').next('ul').prepend(`
        <div style="padding:0px 5px">
        <b id=de>扣分颜色:</b>
        <form id=de>
            <input type=radio name=de value=red>红</input>
            <input type=radio name=de value=orange>橙</input>
            <input type=radio name=de value=yellow>黄</input>
            <input type=radio name=de value=green>绿</input>
            <input type=radio name=de value=blue>蓝</input>
            <input type=radio name=de value=purple>紫</input>
            <input type=radio name=de value=custom>自定义</input>
            <input type=color class=selectedColor></input>
            <input type=button value=√></input>
        </form>
        <b id=na>N/A颜色:</b>
        <form id=na>
            <input type=radio name=na value=red>红</input>
            <input type=radio name=na value=orange>橙</input>
            <input type=radio name=na value=yellow>黄</input>
            <input type=radio name=na value=green>绿</input>
            <input type=radio name=na value=blue>蓝</input>
            <input type=radio name=na value=purple>紫</input>
            <input type=radio name=na value=custom>自定义</input>
            <input type=color class=selectedColor></input>
            <input type=button value=√></input>
        </form>
        </div>
        `);
        //颜色选项初始化
        $('form#de,form#na').each(function(){
            const curColor= $(this).attr('id')==='de'?
                  GM_getValue($(this).prev().text(),'red') : GM_getValue($(this).prev().text(),'green');
            $(this).prev().css('color',curColor);
            $(this).children('.selectedColor').attr('id',curColor);
            if(curColor.indexOf('#')<0){
                $(this).children('input[value='+curColor+']').attr('checked',true);
                $(this).children('.selectedColor').hide();
            }
            else{
                $(this).children('input[value=custom]').attr('checked',true);
                $(this).children('.selectedColor').val(curColor);
            }
        });
        //点击选项颜色改变
        $('form#de,form#na').children(':radio').on('click',function(){
            if($(this).val()==='custom'){
                $(this).next().show();
                $(this).next().attr('id',$(this).next().val());
            }
            else{
                $(this).nextAll('.selectedColor').hide();
                $(this).nextAll('.selectedColor').attr('id',$(this).val());
            }
            $(this).parent().prev().css('color',$(this).nextAll('.selectedColor').attr('id'));
        });
        //自定义颜色改变
        $('form#de,form#na').children('.selectedColor').on('input',function(){
            $(this).attr('id',$(this).val());
            $(this).parent().prev().css('color',$(this).val());
        });
        //确认更改
        $('form#de,form#na').children(':button').on('click',function(){
            GM_setValue($(this).parent().prev().text(),$(this).prev().attr('id'));
            $(this).after('<b>保存成功</b>');
            setTimeout(()=>{
                $(this).next().remove();
            },3000);
        });
    }
    /*在顶端菜单栏添加MOassist设置按钮*/


    /*置顶置底*/
    function GOTOPBOTTOM(){
        const scrollBar=$(document).height()>(window.innerHeight+1||document.documentElement.clientHeight);//如有滚动条
        if(scrollBar&&document.location.href.indexOf('alias=knowledgebase')===-1){//knowledgebase页面自带置顶按钮,不启用
            const goTopBottomButton=document.createElement('div');
            const toggleButton=document.createElement('img');
            $(toggleButton).appendTo(goTopBottomButton);
            $(goTopBottomButton).appendTo($('body')[0]);
            $(goTopBottomButton).css({'position':'fixed','zIndex':10000}).attr('id','goTopBottom');
            $(toggleButton).css({'display':'block','cursor':'pointer'}).attr('src','/knowledgebase/images/arrow_back_to_top.svg');//按钮显示图片(向下箭头)

            //以下按钮参数可自定义修改
            goTopBottomButton.style.bottom='50px';//按钮距离网页底部50px
            goTopBottomButton.style.right='30px';//按钮距离网页右边30px
            toggleButton.style.width='25px';//按钮图片宽25px
            toggleButton.style.height='25px';//按钮图片高25px
            toggleButton.style.opacity=0.5;//按钮不透明度,0.0(完全透明)到1.0(完全不透明)
            toggleButton.style.backgroundColor='grey';//按钮背景颜色,也可使用在excel等软件的自定义颜色界面的16进制代码
            const clickScrollTime=500;//点击按钮时,网页滚动到顶部或底部需要的时间,单位是毫秒

            //点击按钮时网页滚动到顶部或底部
            let scrollDirection='down';
            toggleButton.addEventListener('click',()=>{
                if(scrollDirection==='up'){
                    $('html,body').animate({scrollTop:'0px'},clickScrollTime);
                }
                else{
                    $('html,body').animate({scrollTop:$(document).height()},clickScrollTime);
                }
            });
            //页面滚动监听
            let scrollAction=window.pageYOffset;
            $(window).scroll(()=>{
                const diffY=scrollAction-window.pageYOffset;
                scrollAction=window.pageYOffset;
                scrollDirection= diffY<0? 'down' : 'up';
                toggleButton.style.transform= diffY<0? 'rotate(0deg)' : 'rotate(180deg)';
                if(getScrollTop()===0){
                    scrollDirection='down';
                    toggleButton.style.transform='rotate(0deg)';
                }
                if(getScrollTop()+window.innerHeight+20>=$(document).height()){
                    scrollDirection='up';
                    toggleButton.style.transform='rotate(180deg)';
                }
            });
        }
    }

    //获取垂直方向滑动距离
    function getScrollTop(){
        let scrollTop=0;
        if(document.documentElement&&document.documentElement.scrollTop){
            scrollTop=document.documentElement.scrollTop;
        }
        else if(document.body){
            scrollTop=document.body.scrollTop;
        }
        return scrollTop;
    }
    /*置顶置底*/

    /*卸载置顶置底*/
    function unGOTOPBOTTOM(){
        if($('div#goTopBottom').length) $('div#goTopBottom').remove();
    }
    /*卸载置顶置底*/


    /*菜单遮罩*/
    function COVERMENU(){
        const menu=$('div#menu');
        if(menu.length){
            //若存在menu则添加cover层
            const cover = document.createElement('div');
            cover.className = 'layout';
            cover.style = 'top:'+menu[0].style.top+';opacity:0.3;z-index:10000;right:10%';
            $(cover).appendTo($('body')[0]).attr('id','cover');
            //点击时将cover层下置
            cover.addEventListener('click',()=>{
                cover.style.zIndex = -1;
            });
            //离开menu时cover层还原
            menu[0].addEventListener('mouseleave',()=>{
                cover.style.zIndex = 10000;
            });
            //cover层位置跟随menu 【https://www.minerva-online.com/portal/menu/js/v2/menuRender.js?version=21-08 onScrollEventHandler : 】
            $(window).scroll(()=>{
                const SM=unsafeWindow.SM;
                const ind = SM.ui.headerHeight - SM.ui.getScrollTop();
                cover.style.top= ind>0? ind+'px' : '0px';
            });
        }
    }
    /*菜单遮罩*/

    /*卸载菜单遮罩*/
    function unCOVERMENU(){
        if($('div#cover').length) $('div#cover').remove();
    }
    /*卸载菜单遮罩*/


    /*附件下载*/
    function DOWNLOADFILE(){
        if (document.location.href.indexOf('alias=smngr.surveyexplorer')>=0&&$('tr.persist-header').length){
            $('tr.persist-header').each(function(){
                $(this).children().first().after($(this).children().first().clone(true));
            });
            $('div.sticky-wrap').find(':checkbox').each(function(){//checkbox后添加下载按钮
                const surveyid=$(this).val();
                $(this).parent().after('<td><button type=button id='+surveyid+' class=download><b>↓</td>');
                $('#'+surveyid+'.download').one('click',()=>{
                    DownloadButton(surveyid);
                });
            });
        }
    }

    //获取附件列表
    function DownloadButton(surveyid){
        $('button#'+surveyid+'.download').hide();
        $('button#'+surveyid+'.download').after('<p id='+surveyid+' class=loading><b>......');
        $.get('/open/data.asp?post={"action":"exec","dataset":{"datasetname":"/Apps/SM/Survey/SurveyInstanceGetData"},"parameters":[{"name":"SurveyInstanceID","value":"'+surveyid+'"}]}',(data,status)=>{//调用API获取当前survey数据[SurveyInstanceGetData]
            if (status==='success'){
                const filedata=data.dataset.data[3];
                const fileno=filedata.length;
                $('p#'+surveyid+'.loading').after('<ol id='+surveyid+' class=filelist>\t#='+fileno+'');
                if (fileno>0){
                    for(let i in filedata){
                        const filename=filedata[i].FileName+'.'+filedata[i].FileExtension;
                        const fileid=filedata[i].AttachmentID;
                        const fileurl='/mystservices/Attachments/getAttachment.asp?Attachment='+fileid+'&Password='+filedata[i].Password+'';
                        let filesize=Number(filedata[i].FileSizeInBytes)/1024;
                        filesize= (filesize>1024)? (filesize/1024).toFixed(2)+' MB' : filesize.toFixed(2)+' KB';
                        $('<tr id='+fileid+'>').appendTo('ol#'+surveyid+'.filelist');
                        $(`<td><li><a id=${surveyid} class='${filedata[i].AttachmentType} mailboxlink' href=${fileurl}>${filename}</a>`).appendTo('tr#'+fileid);
                        $('<td>'+filesize+'</td>').appendTo('tr#'+fileid);
                    }
                    $('a#'+surveyid+'.I,a#'+surveyid+'.V').mouseenter(function(){
                        FilePreview(1,$(this).attr('href'));
                    }).mouseleave(()=>{
                        FilePreview(0);
                    });
                    $('ol#'+surveyid+'.filelist').prepend('<button type=button id='+surveyid+' class=yes><b>√');
                    $('button#'+surveyid+'.yes').on('click',()=>{
                        DownloadAll(surveyid);
                    });
                    DownloadButton0(surveyid);
                }
                else {
                    DownloadButton0(surveyid);
                }
            }
            else {
                DownloadButton0(surveyid);
            }
        },"json");
    }

    //预览附件图片
    function FilePreview(show,src){
        if(show){
            const imgid=src.split('=')[2];
            if($('img#'+imgid+'.filepreview').length===0){
                $('<div><img id='+imgid+' class=filepreview>').appendTo('body');
                $('img#'+imgid+'.filepreview').attr('src',src+'&getThumbnail=1').css('height','200px')//视频附件预览图&getThumbnail=1
                    .parent().css({'position':'fixed','zIndex':10000,'height':'200px','background':'url(/images/icons/filtersv2/loading06.gif)'});
            }
            $('img#'+imgid+'.filepreview').parent().css({'top':event.clientY-200+'px','left':event.clientX+100+'px'});
            $('img#'+imgid+'.filepreview').show();
        }
        else{
            $('img.filepreview').hide();
        }
    }

    //按钮变为关闭
    function DownloadButton0(surveyid){
        $('p#'+surveyid+'.loading').remove();
        $('button#'+surveyid+'.download').one('click',()=>{
            DownloadButton1(surveyid);
        });
        $('button#'+surveyid+'.download').text('×');
        $('button#'+surveyid+'.download').show();
    }

    //按钮重置为初始
    function DownloadButton1(surveyid){
        $('ol').remove('#'+surveyid);
        $('button#'+surveyid+'.download').one('click',()=>{
            DownloadButton(surveyid);
        });
        $('button#'+surveyid+'.download').text('↓');
    }

    //下载全部
    function DownloadAll(surveyid){
        $('button#'+surveyid+'.yes').hide();
        const iframe=$('ol#'+surveyid+'.filelist').find('iframe');
        if(iframe.length)iframe.remove();
        setTimeout(()=>{
            $('button#'+surveyid+'.yes').show();
        },1000*$('ol#'+surveyid+'.filelist').find('a').length);//有几个附件就隐藏按钮几秒
        $('ol#'+surveyid+'.filelist').find('a').each(function(){
            $('<iframe src='+$(this).attr('href')+'>').appendTo(this).hide();
        });
        $('button#'+surveyid+'.yes').text('〇');
    }
    /*附件下载*/

    /*卸载附件下载*/
    function unDOWNLOADFILE(){
        if (document.location.href.indexOf('alias=smngr.surveyexplorer')>=0&&$('tr.persist-header').length){
            $('tr.persist-header').each(function(){
                $(this).children().first().remove();
            });
            $('button.download').each(function(){
                $(this).parent().remove();
            });
        }
    }
    /*卸载附件下载*/


    /*扣分标记*/
    function MARKQUESTION(){
        if(document.location.href.indexOf('alias=survey.view')>=0){
            $('span.surveyansweroption').each(function(){
                if($(this).prev('input').is(':checked')){
                    if($(this).prev('input').val()==='__na__'){
                        $(this).css('color','green');//标绿n/a项
                    }
                }
            });
            //获取所有扣分的题目
            const qidmark=[];
            $.get('/mystservices/v2new/getSurvey.asp?InstanceID='+$('input#instanceID').val(),(data,status)=>{
                if (status==='success'){
                    $(data).find('nobr').each(function(){
                        const score=$(this).text();
                        if(score!=''&&score.indexOf('%')===-1){//排除空值与section总分
                            const pts=score.split('/');
                            if(pts[0]<pts[1]){
                                const QidANS=$(this).parent().parent().parent().parent().parent('td.surveyquestioncell').prev().find('div').attr('id');
                                qidmark.push(QidANS);
                            }
                        }
                    });
                    for(let i in qidmark){
                        $('div#'+qidmark[i]).find('span.surveyansweroption').css('color','red');//标红扣分项
                    }
                }
            });
        }
    }
    /*扣分标记*/

    /*卸载扣分标记*/
    function unMARKQUESTION(){
        if(document.location.href.indexOf('alias=survey.view')>=0) $('span.surveyansweroption').removeAttr('style');
    }
    /*卸载扣分标记*/


    /*评论编辑*/
    function COMMENTEDIT(){
        if(document.location.href.indexOf('alias=survey.view')>=0){
            $('<div id=commentEdit>').appendTo($('body')[0])
                .css({'position':'fixed','zIndex':10000,
                      'right':'30px','bottom':'80px','height':'25px','width':'25px',
                      'background':'url("/images/icons/menu/x32/survet.png") 100%/100% #4C5157'})
                .on('click',()=>{
                commentEditSwitch();
            });
            $('<div id=commentFunc>').appendTo('div#commentEdit')
                .css({'position':'fixed','right':'60px','bottom':'50px'}).hide()
                .on('click',e=>{
                e.stopPropagation();//阻止子元素执行父元素click事件
            });
            //提示开关
            $('<b id=hint>【点击获取提示】</b>').appendTo('div#commentFunc');
            $('b#hint').on('click',function(){
                hintSwitch(this);
            });
            //评论匹配与替换
            $('<button type=button id=replaceAll class=surveyBottomButton>一键替换</button>').appendTo('div#commentFunc');
            $('button#replaceAll')
                .before('<textarea id=find placeholder=匹配内容></textarea><b id=commentMark>↓↓↓</b><textarea id=replace placeholder=替换内容></textarea>')
                .before('<b id=findNum>#</b>');
            $('textarea#find,textarea#replace').on('keydown',e=>{
                e.stopPropagation();//阻止页面自带keydown事件修改textarea的class值
            });
            $('b#commentMark').on('click',()=>{
                commentMark();
            });
            $('textarea#find').on('input',function(){
                commentMatch(this);
            });
            $('button#replaceAll').on('click',()=>{
                commentReplace();
            });
            //首字母大写
            $('<button type=button id=initialUpper class=surveyBottomButton>首字母大写</button>').appendTo('div#commentFunc');
            $('button#initialUpper').on('click',()=>{
                initialUpper();
            });
            //评论翻译
            $('<button type=button id=commentTrans class=surveyBottomButton>评论翻译</button>').appendTo('div#commentFunc');
            $('<select id=toLang><option value=en>→英文</option><option value=zh>→中文</option>').appendTo('div#commentFunc');
            $('button#commentTrans').on('click',()=>{
                commentTranslate($('select#toLang option:selected').val());
            });
            $('div#commentFunc').children().css({'display':'block','text-align':'center','margin':'5px auto'});
        }
    }

    //评论替换开关
    function commentEditSwitch(){
        const on=$('div#commentFunc').css('display');
        if(on==='none'){
            $('div#commentFunc').show();
            commentMatch($('textarea#find'));
        }
        else{
            $('div#commentFunc').hide();
            $('textarea.surveycomment,textarea.active').css('background','');
        }
    }

    //插入或移除提示
    function hintSwitch(self){
        if($(self).children().length){
            $(self).text('【点击获取提示】').children().remove();
        }
        else{
            $(self).text('【点击关闭提示】')
                .append('<a class=mailboxlink target=_blank href=https://tool.oschina.net/uploads/apidocs/jquery/regexp.html>匹配支持正则表达式</a>')
                .append('<a class=mailboxlink target=_blank href=https://c.runoob.com/front-end/854/>正则表达式测试</a>')
                .append(`
                <ol>
                    <li>正则实例:[。|.]$ 可匹配末尾处中英文句号;^[a-z] 可匹配开头处小写字母;甲|乙|丙 可匹配甲或乙或丙</li>
                    <li>可当作一般替换使用,如需替换一些特殊字符(\^$*+?.等,参照第一个链接中所列字符),请在前面使用\\标记转义,避免识别为正则表达</li>
                    <li>评论框激活后按Ctrl可切换评论框是否标红,标红的评论框将被排除在修改范围之外,点击两框间的↓↓↓可快速切换全部评论框标红与否</li>
                    <li>匹配内容为空时会匹配所有字符</li>
                </ol>
                `);
            $(self).children().css('display','block').on('click',e=>{
                e.stopPropagation();
            });
            $(self).find('li').css({'text-align':'left','width':'200px'});
        }
    }

    //切换所有评论框标红与否
    function commentMark(){
        $('textarea.surveycomment,textarea.active').each(function(){
            if($(this).attr('class')==='active'){
                $(this).attr('class','surveycomment');
            }
            else{
                $(this).attr('class','active');
            }
        });
    }

    //即时标灰匹配到的评论框并计数
    function commentMatch(self){
        let find;
        try{//若不是正则表达式,按普通字符处理
            find=new RegExp($(self).val(),'gm');
        }
        catch(e){
            find=$(self).val();
        }
        let findNum=0;
        $('textarea.active').css('background','');
        $('textarea.surveycomment').each(function(){
            try{//
                if($(this).val().search(find)>=0){//search只接受正则
                    findNum++;
                    $(this).css('background','lightgrey');
                }
                else{
                    $(this).css('background','');
                }
            }
            catch(e){
                if($(this).val().indexOf(find)>=0){//indexOf只接受字符
                    findNum++;
                    $(this).css('background','lightgrey');
                }
                else{
                    $(this).css('background','');
                }
            }
        });
        $('b#findNum').text('#='+findNum);
    }

    //判断是否为正则并进行评论替换
    function commentReplace(){
        $('textarea.surveycomment').each(function(){
            let find;
            try{
                find=new RegExp($('textarea#find').val(),'gm');
            }
            catch(e){
                find=$('textarea#find').val();
            }
            const replace=$('textarea#replace').val();
            const text=$(this).val().replace(find,replace);
            $(this).val(text);
        });
    }

    //首字母大写
    function initialUpper(){
        $('textarea.surveycomment').each(function(){
            const match=new Set($(this).val().match(/(^|\.|\?|!)("|'|) *[a-z]/gm));
            if(match.size){
                let text=$(this).val();
                for(let m of match){
                    const trans=m.search(/ {2,}/)? m.replace(/ {2,}/,' ') : m;
                    text=text.replace(trans,trans.toUpperCase());
                }
                $(this).val(text);
                $(this).css('background','lightgrey');
            }
            else{
                $(this).css('background','');
            }
        });
    }

    //调用百度翻译进行评论翻译
    async function commentTranslate(toLang){
        await translate_baidu_startup();
        $('textarea.surveycomment').each(async function(){
            if($(this).val()&&$(this).next().is('input:hidden')){
                $(this).after('<textarea id=trans style=overflow:hidden rows='+$(this).attr('rows')+' cols='+$(this).attr('cols')+'>')
                    .after('<button type=button class=attachmentBtn style="display:block;height:1.5em;width:1.5em;margin:5px 0">↑</button>');
            }
            if($(this).val()){
                const translated=await translate_baidu(toLang,$(this).val());
                $(this).next().next('textarea').val(translated);
                unsafeWindow.updrowH($(this).next().next('textarea')[0]);//调用页面自带函数来调整评论框高度
                $(this).next('button').on('click',function(){
                    const prev=$(this).prev().val();
                    const next=$(this).next().val();
                    $(this).prev().val(prev+'\n\n'+next);
                    unsafeWindow.updrowH($(this).prev()[0]);
                    $(this).next().remove();
                    $(this).remove();
                });
            }
        });
        $('textarea#trans').on('keydown',e=>{
            e.stopPropagation();//阻止页面自带keydown事件修改textarea的class值
        });
    }

    //百度翻译 参考https://greasyfork.org/scripts/378277
    async function translate_baidu_startup(){
        if(window.sessionStorage.getItem('baidu_gtk')&&window.sessionStorage.getItem('baidu_token'))return;
        const options = {
            method:'GET',
            url:'https://fanyi.baidu.com',
        };
        const res = await Request(options);
        window.sessionStorage.setItem('baidu_gtk',/window\.gtk = '(.*?)'/.exec(res.responseText)[1]);
        window.sessionStorage.setItem('baidu_token',/token: '(.*?)'/.exec(res.responseText)[1]);
    }

    async function translate_baidu(toLang,raw,fromLang){
        if(!fromLang){
            fromLang = await check_lang(raw);
        }
        const proc_raw = raw.length>30? (raw.substr(0,10)+raw.substr(~~(raw.length/2)-5,10)+raw.substr(-10)) : raw;//process
        const tk_key = window.sessionStorage.getItem('baidu_gtk');
        const token = window.sessionStorage.getItem('baidu_token');//get token
        const options = {
            method:"POST",
            url:'https://fanyi.baidu.com/v2transapi',
            data:'from='+fromLang+'&to='+toLang+'&query='+encodeURIComponent(raw)+'&transtype=translang&simple_means_flag=3&sign='+tk(proc_raw,tk_key)+"&token="+token+"&domain=common",
            headers: {
                "referer": 'https://fanyi.baidu.com',
                "Content-Type": 'application/x-www-form-urlencoded; charset=UTF-8',
            },
        };
        return await BaseTranslate('百度翻译',raw,options,res=>JSON.parse(res).trans_result.data.map(item=>item.dst).join('\n'));
    }

    async function check_lang(raw){
        const options = {
            method:"POST",
            url:'https://fanyi.baidu.com/langdetect',
            data:'query='+encodeURIComponent(raw.replace(/[\uD800-\uDBFF]$/, "").slice(0,50)),
            headers: {
                "Content-Type": "application/x-www-form-urlencoded",
            }
        };
        const res = await Request(options);
        try{
            return JSON.parse(res.responseText).lan;
        }catch(err){
            console.log(err);
            return;
        }
    }

    //根据翻译字符获取sign值
    function tk(a,b){
        var d = b.split(".");
        b = Number(d[0]) || 0;
        for (var e = [], f = 0, g = 0; g < a.length; g++) {
            var k = a.charCodeAt(g);
            128 > k ?
                e[f++] = k : (
                2048 > k ?
                e[f++] = k >> 6 | 192 : (
                    55296 == (k & 64512) && g + 1 < a.length && 56320 == (a.charCodeAt(g + 1) & 64512) ? (
                        k = 65536 + ((k & 1023) << 10) + (a.charCodeAt(++g) & 1023),
                        e[f++] = k >> 18 | 240,
                        e[f++] = k >> 12 & 63 | 128
                    ) :
                    e[f++] = k >> 12 | 224,
                    e[f++] = k >> 6 & 63 | 128
                ),
                e[f++] = k & 63 | 128
            );
        }
        a = b;
        for (f = 0; f < e.length; f++)a = Fo(a+e[f], "+-a^+6");
        a = Fo(a, "+-3^+b+-f");
        a ^= Number(d[1]) || 0;
        0 > a && (a = (a & 2147483647) + 2147483648);
        a %= 1E6;
        return a.toString() + "." + (a ^ b);
    }

    function Fo(a,b) {
        for (var c = 0; c < b.length - 2; c += 3) {
            var d = b.charAt(c + 2);
            d = "a" <= d ? d.charCodeAt(0) - 87 : Number(d);
            d = "+" == b.charAt(c + 1) ? a >>> d : a << d;
            a = "+" == b.charAt(c) ? a + d & 4294967295 : a ^ d;
        }
        return a;
    }

    //异步请求包装工具
    async function PromiseRetryWrap(task,options,...values){
        const {RetryTimes,ErrProcesser} = options||{};
        let retryTimes = RetryTimes||5;
        const usedErrProcesser = ErrProcesser || (err =>{throw err;});
        if(!task)return;
        while(true){
            try{
                return await task(...values);
            }catch(err){
                if(!--retryTimes){
                    console.log(err);
                    return usedErrProcesser(err);
                }
            }
        }
    }

    async function BaseTranslate(name,raw,options,processer){
        const toDo = async ()=>{
            let tmp;
            try{
                const data = await Request(options);
                tmp = data.responseText;
                const result = await processer(tmp);
                window.sessionStorage.setItem(name+'-'+raw,result);
                return result;
            }catch(err){
                throw {
                    responseText: tmp,
                    err: err
                };
            }
        };
        return await PromiseRetryWrap(toDo,{RetryTimes:3,ErrProcesser:()=>"翻译出错"});
    }

    function Request(options){
        return new Promise((reslove,reject)=>GM_xmlhttpRequest({...options,onload:reslove,onerror:reject}));
    }
    /*评论编辑*/


    /*卸载评论编辑*/
    function unCOMMENTEDIT(){
        if($('div#commentEdit').length) $('div#commentEdit').remove();
    }
    /*卸载评论编辑*/


    /*验证输出*/
    function VERIFYEXPORT(){
        if (document.location.href.indexOf('alias=smngr.surveyexplorer')>=0&&$('div#filterdiv').length){
            $('div#filterdiv').before('<button type=button id=verifyExport class="rm-btn rm-btn-default">验证输出勾选的报告</button>');
            $('button#verifyExport').css({'margin':'10px 0px','display':'block'}).on('click',()=>{
                verifyExportAll();
            });
        }
    }

    //验证输出全部报告
    function verifyExportAll(){
        const apply=confirm('请确认是否要验证输出当前页面勾选的所有报告(电脑配置低请勿一次性输出过多报告)');
        if(apply){
            $('table#reporttable tbody').find('tr').each(function(){
                if($(this).find('input:checkbox').eq(0).is(':checked')){
                    const a=$(this).find('a.mailboxlink')[0];
                    const src=$(a).attr('href');
                    const iframe=document.createElement('iframe');
                    iframe.src=src;
                    iframe.style='height:80px; width:250px';
                    $(a).after(iframe);
                    iframe.onload=function(){
                        const doc=$(this).contents();
                        $(doc).find('div#addInfo,div#menu,div#pathContainer').remove();
                        if($(doc).find('input#scrverN').is(':checked')&&$(doc).find('input#questVerN').is(':checked')){//前2点均为否时才进行操作
                            $(doc).find('input#scrverY').click();
                            $(doc).find('input#questVerY').click();
                            $(doc).find('button#save').click();
                        }
                    };
                }
            });
            alert('请耐心等待所有小窗口加载完成,显示绿色保存成功提示后,再刷新页面检查是否全部验证输出成功');
        }
    }
    /*验证输出*/

    /*卸载验证输出*/
    function unVERIFYEXPORT(){
        if($('button#verifyExport').length) $('button#verifyExport').remove();
    }
    /*卸载验证输出*/


})();