免Flash文件上传

无需调用Flash,从课程平台上传附件,不必为了传作业多装一个浏览器!

目前為 2021-09-20 提交的版本,檢視 最新版本

// ==UserScript==
// @name              免Flash文件上传
// @name:en           Upload without Flash
// @namespace         https://gf.qytechs.cn/zh-CN/users/605474
// @version           1.2
// @description       无需调用Flash,从课程平台上传附件,不必为了传作业多装一个浏览器!
// @description:en    No need to call Flash, upload accessories from the course platform, do not have to make multiple browsers for the homework!
// @author            Ziu
// @match             *://cc.bjtu.edu.cn:81/*
// @match             *://cc.bjtu.edu.cn:81/meol/common/hw/student/write.jsp?hwtid=*
// @icon              https://gitee.com/ziuc/utool-filebed/raw/master/20210514-231824-0795.png
// @require           https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js
// @require           https://cdn.bootcdn.net/ajax/libs/jquery/1.7.2/jquery.min.js
// @grant             none
// @license           MIT
// ==/UserScript==

(function() {
    'use strict';
    // 上传回调函数全局变量
    let index = 0;
    let isAbort = 0;
    let oloaded = 0;
    let ot = 0;

    // 预置DOM
    let frontTag = "<li><a id='add_button' title='上传作业' onclick=location='http://cc.bjtu.edu.cn:81/meol/common/hw/student/hwtask.jsp?tagbug=client&strStyle=new06'><span>上传作业</span></a></li>";
    let uploadBox = '<tr><td><div id="outerDiv" style="font-size: 14px; width: 550px; margin:0 auto; margin-top: 10px;"><div id="inputDiv" title="点击选择文件上传" style="height: 200px; width: 560px; cursor:pointer; border: 3px dashed; border-radius:10px; border-color: #82b900; background: #c6f062;"><div id="inputArea"><div id="textShow" style="margin-top: 80px; font-size: 20px; color: #5c6b77; text-align: center;"><p id="p1">📁文件上传📝</p><p id="p2" style="font-size: 15px">(支持拖拽上传文件)</p></div><input id="currentFile" type="file" multiple="multiple" style="display:none;" </input></div></div><div id="filenames" style="margin-top: 10px; margin-bottom: 10px; background-color: #e7e8e0;"></div><div id="buttonDiv" style="margin-top: 10px; margin-bottom: 10px; text-align: center"></div></div></td></tr>'
    let uploadBtn = '<a id="uploadTrigger" title="上传" style="cursor:pointer; padding-top: 2.5px; padding-bottom: 2.5px; padding-right: 5px; padding-left: 5px; background-color: #c6f062; border: 2px solid;">上传</a>&nbsp&nbsp';
    let emptyBtn = '<a id="emptyTrigger" title="清空" style="cursor:pointer; padding-top: 2.5px; padding-bottom: 2.5px; padding-right: 5px; padding-left: 5px; background-color: #c6f062; border: 2px solid;">清空</a>';

    // 外部DOM操作
    $('#tmenu').append(frontTag);
    $('.infotable>tbody>tr:contains("请输入你的答案")').after(uploadBox);

    // 信息显示部分
    let upldIconList = ['🕒','⚡','✅','🕒','⌛','🔒','✅']; // 所有icon统一管理
    let infoIconList = ['🔄','⚠','🚫','🕒','⌛','🔒','✅']; // 所有icon统一管理

    // 动效
    $('#inputDiv').mouseenter(function (){$('#inputDiv').css('background-color','#87bd04');$('#textShow').css('color','#e7e8e0')});
    $('#inputDiv').mouseleave(function (){$('#inputDiv').css('background-color','#c6f062');$('#textShow').css('color','#5c6b77')});
    $('tr').mouseenter(function(){$(this).css('background','#f2f2f2')});
    $('tr').mouseleave(function(){$(this).css('background','#ffffff')});

    // 文件选择前事件监听
    $('#inputDiv').click(function (){$('#currentFile').trigger('click');});
    $('#currentFile').change(fileChangedByInput);

    function fileChangedByInput(){
        let filelist = $('#currentFile')[0].files;
        // 缓存区展示
        $('#inputDiv').hide(); // 隐藏上传框
        $('#filenames, #buttonDiv').empty(); // 先清空 再插入
        let sizeType = getSizeType(filelist);
        let nameType = getNameType(filelist); // todo
        for(let i=0;i<filelist.length;i++){
            let item = {};
            item.file = filelist[i];
            item.sizeType = sizeType[i];
            item.initName = item.file.name;
            item.showName = nameType[i];
            let fileObject = '<div class="fileObjects" id="fileTh'+i+'"style="cursor:default; margin-top: 10px; background-color: #e7e8e0;background-image: url(http://cc.bjtu.edu.cn:81/meol/styles/newstyle/course/new06/body_bg.jpg); background-repeat:no-repeat; background-size: 0%;"><a class="fileindex" id="fileindex'+i+'" title="[文件]" style="margin-left: 5px;">📄</a><a class="filename" title="'+item.initName+'">&nbsp&nbsp|&nbsp&nbsp'+item.showName+' ('+item.sizeType.size+item.sizeType.type+')'+'</a><a class="uploadSpeed" id="speedTh'+i+'" title="上传速度"></a><a class="timeRemain" id="timeRemainTh'+i+'"></a></div>';
            $('#filenames').append(fileObject);
        }

        // 文件选择后外部DOM插入
        $('#buttonDiv').append(uploadBtn);
        $('#buttonDiv').append(emptyBtn);

        // 文件选择后事件监听
        $('#emptyTrigger').click(function (){$('#currentFile').val('');$('#filenames, #buttonDiv').empty();$('#inputDiv').show();isAbort=1;});
        $('#uploadTrigger').click(function (){
            // 处理文件缓存区
            $('#uploadTrigger').hide();
            $('#uploadTrigger').css('cursor','not-allowed');
            isAbort = 0; // 按上传之前按过清空,将isAbort置回0
            sendFileMsg();
            function sendFileMsg(){
                if(index >= filelist.length){
                    // 递归结束
                    $('#currentFile').val(''); // <input>文件清空
                    $('#emptyTrigger').css('cursor','pointer');
                    index = 0; // 递归条件置零
                    return // 结束递归
                }

                let formData = new FormData();
                formData.append('Filename', filelist[index].name);
                formData.append('Filedata', filelist[index]);

                let xReq = new XMLHttpRequest();
                xReq.open('POST','http://cc.bjtu.edu.cn:81/meol/servlet/SerUpload');
                xReq.addEventListener("load", onSuccess);
                xReq.addEventListener("error", onError);
                xReq.upload.onloadstart = onStart;
                xReq.upload.onprogress = onProgress;
                xReq.upload.onabort = onAbort;
                xReq.send(formData);

                function onStart(){
                    ot = new Date().getTime(); // 设置上传开始时间,用以计算时间速度
                    oloaded = 0; // 设置上传开始时,已上传的文件大小为0
                }

                function onProgress(evt){
                    if(isAbort==1){
                        xReq.abort(); // 上传过程中随时检查,终止请求
                    }
                    // 进度计算
                    let percentage;
                    percentage = (evt.loaded * 100 / evt.total).toFixed(0);

                    // 速度计算
                    let nt = new Date().getTime(); // 获取当前时间
                    let perTime = (nt-ot)/1000; // 计算出上次调用该方法时到现在的时间差,单位为s
                    ot = new Date().getTime(); //重新赋值,用以下次计算
                    let perLoad = evt.loaded - oloaded; // 计算该分段上传的文件大小,单位b
                    oloaded = evt.loaded; // 重新赋值,用以下次计算
                    let speed = perLoad/perTime; // 单位 B/s
                    let bspeed = speed;
                    let Sunits = 'B/s';
                    if(speed/1024>1){
                        speed = speed/1024;
                        Sunits = 'KB/s'
                    }
                    if(speed/1024>1){
                        speed = speed/1024;
                        Sunits = 'MB/s';
                    }
                    speed = speed.toFixed(1);

                    // 时间计算 文件>100MB触发
                    if(evt.total>104857600){
                        let restTime = ((evt.total-evt.loaded)/bspeed).toFixed(0);
                        // 更新文件缓存区
                        $('#timeRemainTh'+index).html('&nbsp | &nbsp'+upldIconList[0]+restTime+'秒');
                    }

                    // 更新文件缓存区
                    $('#fileTh'+index).css('background-size',percentage+'%');
                    $('#speedTh'+index).html('&nbsp | &nbsp'+upldIconList[1]+speed+Sunits);
                }

                function onAbort(){
                    isAbort = 0; // 终止条件置零
                    index = 0; // 请求终止后index也必须归零,因为中止未完成递归,若中止文件index>0则第二次上传请求无法发起
                }

                function onSuccess(){
                    // 插入编辑器操作
                    let myiframe = document.getElementsByTagName('iframe')[1].contentDocument;
                    let textArea = myiframe.getElementsByClassName('cke_show_borders');
                    let constructor = '<p><a data-cke-saved-href="/meol/'+this.responseText+'" href="/meol/'+this.responseText+'">'+filelist[index].name+'</a></p>'
                    $(textArea).append(constructor);

                    // 处理缓存区操作
                    $('#speedTh'+index).html('&nbsp | &nbsp'+upldIconList[2]);
                    $('#speedTh'+index).attr('title','[已上传]');
                    $('#timeRemainTh'+index).remove();
                    $('#fileTh'+index).css('background','#c6f062');

                    // 递归操作
                    index++;
                    sendFileMsg();
                }
                function onError(){
                    alert('上传失败');
                }
            }
        })
    }

    function getSizeType(filelist){
        let RtnsizeType = [];
        for(let item of filelist){
            let sizeTypeTMP = {};
            if(item.size<1024){
                sizeTypeTMP.size = (item.size).toFixed(2);
                sizeTypeTMP.type = 'B';
            }
            else if(item.size>1024&&item.size<1048576){
                sizeTypeTMP.size = (item.size/1024).toFixed(2);
                sizeTypeTMP.type = 'KB';
            }
            else if(item.size>1048576&&item.size<1073741824){
                sizeTypeTMP.size = (item.size/1048576).toFixed(2);
                sizeTypeTMP.type = 'MB';
            }
            else if(item.size>1073741824){
                alert('你选择了大于1GB的文件,服务器存储资源有限,建议选择其他传输方式。');
                sizeTypeTMP.size = (item.size/1073741824).toFixed(2);
                sizeTypeTMP.type = 'GB';
            }
            RtnsizeType.push(sizeTypeTMP);
        }
        return RtnsizeType;
    }

    function getNameType(filelist){
        // 文件名显示长度限制
        let nameType = [];
        let limit = 25;
        for(let item of filelist){
            let splitName = item.name.split('.'); // 预防文件名中含.的情况
            let newName = '';
            for(let i=0;i<splitName.length-1;i++){
                newName = newName + splitName[i];
            }
            if(newName.length>limit){
                newName = newName.slice(0,limit) + '...';
            }
            nameType.push(newName);
        }
        return nameType;
    }

    function judgeOnceInPage(){
        if($("script:contains('该作业不允许重复提交,确定提交作业吗?')").length!=0){
            let newspan = '<span>(只能提交一次)</span>';
            $('span:contains("查看作业任务")').after(newspan);
            alert("注意,此作业只能提交一次,请检查无误后再提交!");
            return 1;
        }
        else return 0;
    }

    function getInfoList(){
        let initInfoList = $('.infolist');
        let initSubmits = $('.enter');
        let infoList = [];
        for(let i=0;i<initInfoList.length;i++){
            let infoTMP = {};
            infoTMP.id = initInfoList[i].getAttribute('href').split('=')[1];
            infoTMP.name = initInfoList[i].innerText;
            for(let j=0;j<initSubmits.length;j++){
                infoTMP.able = (initSubmits[j].getAttribute('href').split('=')[1]==infoTMP.id);
                if(infoTMP.able) break;
            }
            infoList.push(infoTMP);
            appendOnceInfo(infoTMP.id);
            appendSubmitInfo(infoTMP.id);

            function appendOnceInfo(hwtid){
                if(!infoTMP.able){
                    // 过期作业,不发请求
                    return
                }
                // 检查是否只能提交一次
                let url = 'http://cc.bjtu.edu.cn:81/meol/common/hw/student/write.jsp?hwtid='+hwtid;
                let data = 'hwtid='+hwtid;
                let xReq = new XMLHttpRequest();
                xReq.open('GET',url,false); // 注意,此处请求应当为同步请求 否则调用this拿到的数据是undefined
                xReq.addEventListener("load", onSuccess);
                xReq.addEventListener("error", onError);
                xReq.send(data);
                function onSuccess(){
                    let myResponse = this.responseText;
                    if(myResponse.indexOf('该作业不允许重复提交,确定提交作业吗?')!=-1){
                        let attentionIcon = '<a class="attentionIcon" title="此作业只允许提交一次" style="cursor:default;">'+infoIconList[5]+'</a>'
                        $(".infolist[href='hwtask.view.jsp?hwtid="+infoTMP.id+"']").before(attentionIcon);
                    }
                    else {
                        let attentionIcon = '<a class="attentionIcon" title="此作业允许重复提交" style="cursor:default;">'+infoIconList[3]+'</a>'
                        $(".infolist[href='hwtask.view.jsp?hwtid="+infoTMP.id+"']").before(attentionIcon);
                    }
                }
                function onError(){
                    alert('请求失败');
                }
            }

            function appendSubmitInfo(hwtid){
                if(!infoTMP.able){
                    // 过期作业,不发请求
                    return
                }
                // 检查是否已经提交
                let url = 'http://cc.bjtu.edu.cn:81/meol/common/hw/student/taskanswer.jsp?hwtid='+hwtid;
                let data = 'hwtid='+hwtid;
                let xReq = new XMLHttpRequest();
                xReq.responseType = "document";
                xReq.open('GET',url,true); // 注意,此处请求应当为异步请求 用以接收text/html数据
                xReq.addEventListener("load", onSuccess);
                xReq.addEventListener("error", onError);
                xReq.send(data);
                function onSuccess(){
                    let myResponse = this.responseXML;
                    let iptArea = $(myResponse).find("tr:contains('回答的内容')+tr>td>input");
                    if(iptArea.length<=0){
                        let submitIcon = '<a class="submitIcon" title="作业未提交" style="cursor:default;">'+infoIconList[4]+'</a>'
                        $(".infolist[href='hwtask.view.jsp?hwtid="+infoTMP.id+"']").before(submitIcon);
                    }
                    else{
                        let submitIcon = '<a class="submitIcon" title="作业已提交" style="cursor:default;">'+infoIconList[6]+'</a>'
                        $(".infolist[href='hwtask.view.jsp?hwtid="+infoTMP.id+"']").before(submitIcon);
                    }
                }
                function onError(){
                    alert('请求失败');
                }
            }
        }
        return infoList;
    }

    // 页面加载完毕,执行拖拽上传功能
    window.onload = function () {
        if($("span:contains('查看作业任务')").length==0){
            // 判断是否在作业页面
            return
        }
        let oBox = document.getElementById('inputDiv');
        let timer = null;
        document.ondragover = function(){
            clearTimeout(timer);
            timer = setTimeout(function(){
                // 文件放下后执行操作
                $('#p1').html('📁文件上传📝');
                $('#inputDiv').css('background-color','#c6f062');$('#textShow').css('color','#5c6b77');
            },200);
        };
        // 进入子集的时候 会触发ondragover 频繁触发 不给ondrop机会
        oBox.ondragover = function(){
            return false;
        };
        oBox.ondragleave = function(){
            $('#p1').html('📌请将文件拖拽到此区域');
            $('#inputDiv').css('background-color','#87bd04');$('#textShow').css('color','#e7e8e0');
        };
        oBox.ondrop = function(ev){
            $('#currentFile')[0].files = ev.dataTransfer.files;
            fileChangedByInput();
            return false;
        };
    };

    // 列表信息增强与单词提交判断函数触发
    judgeOnceInPage();
    getInfoList();

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址