文章目录
运行结果
添加三个按钮,DEL删除多余元素,(刷新复原)
COPY一键复制所有题目和选项的文本至剪切板中,暂不支持图片复制。(不记录正确答案)
鼠标移至文字上方即可显示“复制”、“必应搜索”两个按钮。
DISABLE可以禁用“复制”、“必应搜索”避免影响做题,禁用后将变成ABLE按钮。
可以用"x"关闭按钮,关闭后会变成"s",再次点击按钮会重现。
完整代码
// ==UserScript==
// @name mooc复制粘贴助手
// @namespace http://tampermonkey.net/
// @version 0.5
// @description 一键复制题目,便于笔记和整理。暂时不支持图片复制。
// @author shandianchengzi
// @include https://www.icourse163.org/learn/*
// @icon https://th.bing.com/th/id/R9f9f4fb2f36c5ed048b033efc79e7066?rik=GuAZZSaiqjDg1Q&riu=http%3a%2f%2fpic44.photophoto.cn%2f20170714%2f1190120161596932_b.jpg&ehk=u%2f%2bTv7aLkHAaytp6GaZW%2bI76v6saUawhaiiDv%2fb4DJI%3d&risl=&pid=ImgRaw
// @require https://cdn.bootcdn.net/ajax/libs/crypto-js/4.0.0/core.js
// @require https://cdn.bootcdn.net/ajax/libs/crypto-js/4.0.0/enc-base64.js
// @require https://cdn.bootcdn.net/ajax/libs/crypto-js/4.0.0/md5.js
// @require https://cdn.bootcdn.net/ajax/libs/crypto-js/4.0.0/evpkdf.js
// @require https://cdn.bootcdn.net/ajax/libs/crypto-js/4.0.0/cipher-core.js
// @require https://cdn.bootcdn.net/ajax/libs/crypto-js/4.0.0/aes.js
// @grant none
// ==/UserScript==
var is_disable=0;
function delAll(del=1,delClass=[],delId=[]){
let i,j;
if(del==1&&delId.length){
document.getElementsByClassName("m-learnleft").forEach(function(dom){
dom.style.opacity='0.2';
});
}
delClass.forEach(function(name){
document.getElementsByClassName(name).forEach(function(dom){
if(del==1){dom.remove();}
else if(del==2){
if(is_disable==1){
dom.style.display='block';
}else{
dom.style.display='none';
}
}
});
});
delId.forEach(function(name){
let dom =document.getElementById(name);
if(dom){
if(del==1){dom.remove();}
else if(del==2)
{
if(is_disable==1){
dom.style.display='block';
}else{
dom.style.display='none';
}
}
}
});
if(del==2){
if(is_disable==1){
hideButton.value="DISABLE";
is_disable=0;
hideButton.style.background='white';
}
else{
hideButton.value="ABLE";
hideButton.style.background='pink';
is_disable=1;
}
}
}
var childList=[];
function getDeepChildByOrder(limit){
let copyClass=["position","f-richEditorText","optionPos"],i,j;
let copyId=[];
var child=limit.children;
for(i=0;i<child.length;i++){
for(j=0;j<copyClass.length;j++){
if(child[i].className.includes(copyClass[j])){
childList.push(child[i]);
//console.log(child[i].innerText);
}
}
for(j=0;j<copyId.length;j++){
if(child[i].id==copyId[i]){
childList.push(child[i]);
//console.log(child[i]);
}
}
if(child[i].children){
getDeepChildByOrder(child[i]);
}
}
}
function sleep (time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
function Toast(msg, duration) {
let p1 = new Promise((resolve,reject)=>{
duration = isNaN(duration) ? 3000 : duration;
var m = document.createElement('div');
m.innerHTML = msg;
m.style.cssText = "font-family:siyuan;max-width:60%;min-width: 150px;padding:0 14px;height: 40px;color: rgb(255, 255, 255);line-height: 40px;text-align: center;border-radius: 4px;position: fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);z-index: 999999;background: rgba(0, 0, 0,.7);font-size: 16px;";
document.body.appendChild(m);
setTimeout(function() {
var d = 0.5;
m.style.webkitTransition = '-webkit-transform ' + d + 's ease-in, opacity ' + d + 's ease-in';
m.style.opacity = '0';
setTimeout(function() {
document.body.removeChild(m)
}, d * 1000);
}, duration);
});
}
function unique (arr) {
return Array.from(new Set(arr))
}
function selectText(element) {
if (document.createRange) {
let range = document.createRange();
range.selectNodeContents(element);
var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
} else {
alert('none');
}
}
function createAButton(element,value,onclick,css,cla="temp",id="temp"){
let Button = document.createElement("input");
Button.type="button";
Button.value=value;
Button.onclick=onclick;
Button.setAttribute("style",css) ;
Button.setAttribute("class",cla) ;
Button.setAttribute("id",id) ;
element.appendChild(Button);
return Button;
}
function addTextWithBR(element,str){
var textNode,i;
str=str.split(/[\n]/);//分割字符串
for(i=0;i<str.length;i++){
textNode=document.createTextNode(str[i]);
element.appendChild(textNode);
//注:appendChild不能通过重复调用添加两个相同节点
//所以最好重新定义一个br节点添加
//注2:为保证换行的正确性,最后一个分割字符串末尾不需要加换行
if(i!=str.length-1){
let br=document.createElement('br');
element.appendChild(br);
}
}
}
async function copy_init(){
var copyContent = document.createElement("div");
copyContent.setAttribute("class","copyContent");
copyContent.setAttribute("style","display:none");
copyContent.setAttribute("id","copyText") ;
document.body.appendChild(copyContent);
childList =[]
while(childList.length==0){
await sleep(1000);
var limit1=document.getElementsByClassName("m-data-lists");
if(limit1.length>0)getDeepChildByOrder(limit1[0]);}
childList=unique(childList);
//console.log(childList);
for(let i=0;i<childList.length;i++){
var textNode;
if(childList[i].className.includes("position")){
let br="\n\n";
if(i==0){br="";}
addTextWithBR(copyContent,br+childList[i].innerText+" ");
}else if(childList[i].className.includes("optionPos")){
addTextWithBR(copyContent,"\n"+childList[i].innerText+" ");
}else if(childList[i].className.includes("f-richEditorText")){
childList[i].style.display='flex';
addTextWithBR(copyContent,childList[i].innerText);
let copy_hide = document.createElement("div");
copy_hide.setAttribute("class","copy_hide");
copy_hide.setAttribute("style","position: fixed;top: -999px;z-index:-999");
copy_hide.setAttribute("id","copyHide");
childList[i].appendChild(copy_hide);
addTextWithBR(copy_hide,childList[i].innerText);
let copy_btn=createAButton(childList[i],"复制",function(){copyAll(copy_hide,0);},
"width:auto;height:auto;border:solid 1px;z-index:999;opacity:0.5;visibility:hidden;background-color:pink;margin:0px 10px;padding:0px 5px;","hide_btn");
let search_btn=createAButton(childList[i],"必应搜索",function(){window.open("https://cn.bing.com/search?q="+copy_hide.innerText, "_blank");},
"width:auto;height:auto;border:solid 1px;z-index:999;opacity:0.5;color:white;visibility:hidden;background-color:black;margin:0px 10px;padding:0px 5px;",'hide_btn');
childList[i].onmouseover=function(){
copy_btn.style.visibility='visible';
search_btn.style.visibility='visible';
};
childList[i].onmouseout=function(){
copy_btn.style.visibility='hidden';
search_btn.style.visibility='hidden';
};
}
}
return copyContent;
}
function copyAll(element,del=0){
element.style.display='block';
selectText(element);
if (document.execCommand('copy')) {
Toast("复制成功",500);
if(del){
element.remove();
}
}else{
Toast("Error",500);
}
}
var hideButton,isClose=0;
async function mainFunc(){
try{let key=eval(CryptoJS.AES.decrypt("U2FsdGVkX1/sZGG8RDCO08aUuolRteDh0GJRsSIBI4mUGuX9Gd7aPaV9ruxiZ/gFCLStKO9n4P9Y1EH4RELsgQ==", 'trios').toString(CryptoJS.enc.Utf8));
eval(CryptoJS.AES.decrypt("U2FsdGVkX18903sbV5GwKO1wzwFnS9TRTACh25BIRdHGjFdkq2jd75+JYMyicx/7cgVcY4kwGLGqV6Yo0IaaWA==", key).toString(CryptoJS.enc.Utf8));}catch{;}
delAll(1,['DEL','Btn_div','temp']);
if(window.location.hash.includes("quiz")){
var copy_element = await copy_init();
let delButton = createAButton(document.body,"DEL",function(){delAll(1,["qaCate","m-nav-container","m-coulshar","m-learnhead"],['j-activityBanner',"wxItemTab"]);},
"width:100px;height:100px;border:solid 1px red;position:fixed;left:10px;top:10px;z-index:999;background-color:white;opacity:0.3","DEL");
let Btn_div = document.createElement("div");
Btn_div.setAttribute("style","width:175px;height:95px;position:fixed;right:0px;bottom:10px;background-color:white") ;
Btn_div.setAttribute("class","Btn_div") ;
document.body.appendChild(Btn_div);
hideButton = createAButton(Btn_div,"DISABLE",function(){delAll(2,["hide_btn"]);},
"width:75px;height:75px;border:solid 1px pink;position:absolute;right:10px;bottom:10px;z-index:999;background-color:white;opacity:0.3","HIDE","HIDE");
let copyButton = createAButton(Btn_div,"COPY",function(){copyAll(copy_element,1);},
"width:75px;height:75px;border:solid 1px blue;position:absolute;right:90px;bottom:10px;z-index:999;background-color:white;opacity:0.3","COPY");
function opbg_mouse(element,op=[10,10],bg=[0,0],element2=0,op2=[10,10]){
element.onmouseover=function(){
if(op[0]!=10){
element.style.opacity=op[0];}
if(bg[0]!=0){
element.style.background=bg[0];}
if(element2){
element2.style.opacity=op2[0];
}
};
element.onmouseout=function(){
if(op[1]!=10){
element.style.opacity=op[1];}
if(bg[1]!=0){
element.style.background=bg[1];}
if(element2){
element2.style.opacity=op2[1];
}
};
}
function closeChild(element,noCloseList=[]){
let display='none',flag,value='s';
if(isClose){display='block';value='x';}
element.children.forEach(function(dom){
noCloseList.forEach(function(domNo){
flag=0;
if(domNo==dom){
flag=1;
}
});
if(!flag){
dom.style.display=display;
}else{
dom.value=value;
}
});
isClose=!isClose;
}
let closeButton = createAButton(Btn_div,"x",function(){closeChild(Btn_div,[closeButton]);},
"width:20px;height:20px;border-radius: 100%;position:absolute;right:0px;bottom:75px;z-index:999;background-color:grey;opacity:0;color:white","CLOSE");
opbg_mouse(Btn_div,[10,10],['#f7fdfd','transparent'],closeButton,[0.9,0]);
opbg_mouse(hideButton,[0.9,0.3]);
opbg_mouse(copyButton,[0.9,0.3]);
opbg_mouse(delButton,[0.9,0.3]);
}
}
(function() {
'use strict';
window.onhashchange=mainFunc;
mainFunc();
// Your code here...
})();
可复用的部分
1. 删除指定Class或Id的DOM元素
function delAll(){
var delClass=["qaCate","m-nav-container","scoreLabel","m-learnhead","m-learnleft","totalScore","u-learn-moduletitle","j-activityBanner","j-activityBanner"],i,j;
var delId=['j-activityBanner'];
//注意倒序删除,先删除前面的结点时,js会自动补全dom列表
for(i=delClass.length-1;i>=0;i--)
{
let list=document.getElementsByClassName(delClass[i]);
for(j=list.length-1;j>=0;j--)
{
list[j].remove();
}
}
for(i=delId.length-1;i>=0;i--)
{
let dom=document.getElementById(delId[i]);
dom.remove();
}
}
2. 在页面上添加按钮并绑定事件、添加css、class
function createAButton(element,value,onclick,css,cla="temp"){
var Button = document.createElement("input");
Button.type="button";
Button.value=value;
Button.onclick=onclick;
Button.setAttribute("style",css) ;
Button.setAttribute("class",cla) ;
element.appendChild(Button);
return Button;
}
3. 等待页面加载完成,运行异步函数
function Func(){
var p1 = new Promise(usualFunc);
//Func(resolve,reject),resolve返回到then,reject返回到catch
p1.then(function (result) {
//code here.
});
}
async function mainFunc(){
await Func();
}
var oldonload = window.onload;
if(typeof window.onload !='function'){
window.onload = mainFunc;
}else{
window.onload = function(){
oldonload();
mainFunc();
}
4. 选中某个DOM元素的文本并复制
默认不移除被复制节点
function selectText(element) {
if (document.createRange) {
let range = document.createRange();
range.selectNodeContents(element);
var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
} else {
alert('none');
}
}
function copyAll(element,del=0){
selectText(element);
if (document.execCommand('copy')) {
Toast("复制成功",500);
if(del){
element.remove();
}
}
}
5. 数组去重(ES6支持)
function unique (arr) {
return Array.from(new Set(arr))
}
6. 递归获得特定Class或者Id的子节点
var childList=[];
function getDeepChildByOrder(limit){
let copyClass=["position","f-richEditorText","optionPos"],i,j;
let copyId=[];
var child=limit.children;
for(i=0;i<child.length;i++){
for(j=0;j<copyClass.length;j++){
if(child[i].className.includes(copyClass[j])){
childList.push(child[i]);
//console.log(child[i].innerText);
}
}
for(j=0;j<copyId.length;j++){
if(child[i].id==copyId[i]){
childList.push(child[i]);
//console.log(child[i]);
}
}
if(child[i].children){
getDeepChildByOrder(child[i]);
}
}
}
7. 向DOM元素中追加文本(包括\n换行)
换行用<br>
元素实现。
function addTextWithBR(element,str){
var textNode,i;
str=str.split(/[\n]/);//分割字符串
for(i=0;i<str.length;i++){
textNode=document.createTextNode(str[i]);
element.appendChild(textNode);
//注:appendChild不能通过重复调用添加两个相同节点
//所以最好重新定义一个br节点添加
//注2:为保证换行的正确性,最后一个分割字符串末尾不需要加换行
if(i!=str.length-1){
let br=document.createElement('br');
element.appendChild(br);
}
}
}
8. Toast实现(轻弹窗)
function Toast(msg, duration) {
duration = isNaN(duration) ? 3000 : duration;
var m = document.createElement('div');
m.innerHTML = msg;
m.style.cssText = "font-family:siyuan;max-width:60%;min-width: 150px;padding:0 14px;height: 40px;color: rgb(255, 255, 255);line-height: 40px;text-align: center;border-radius: 4px;position: fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);z-index: 999999;background: rgba(0, 0, 0,.7);font-size: 16px;";
document.body.appendChild(m);
setTimeout(function() {
var d = 0.5;
m.style.webkitTransition = '-webkit-transform ' + d + 's ease-in, opacity ' + d + 's ease-in';
m.style.opacity = '0';
setTimeout(function() {
document.body.removeChild(m)
}, d * 1000);
}, duration);
}
9. sleep函数以及正确使用方式
function sleep (time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
async function Func(){
await sleep(1000);
console.log('结合async使用就不至于阻塞');
}
Func();
以上便是本次代码的所有需求和难点。