fist version

This commit is contained in:
小钊 2025-06-17 10:20:45 +08:00
parent 99d66d38ac
commit fd41f8558f

402
LMSGuides助手-源码.user.js Executable file
View File

@ -0,0 +1,402 @@
// ==UserScript==
// @name LMSGuides助手-源码
// @version 1.3.2
// @description 要有远大的理想,也要有脚踏实地的本领
// @author 小钊
// @match *://10.90.53.11:5090/*
// @homepageURL https://www.zxqblog.cn
// @grant GM_registerMenuCommand
// @grant GM_unregisterMenuCommand
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// ==/UserScript==
/*
1.3.1
修复
复制到实体机功能无法使用
1.3.2
修复
1.实验报告->文本样式->预定义格式被识别为代码导致添加按钮的bug
2.复制到虚拟机/实体机成功的提示无法切换
*/
(function() {
'use strict';
// 通用样式定义
// 复制到虚拟机的样式
const buttonStyle = `
.copy-vm-btn {
position: absolute;
right: 10px;
top: 10px;
padding: 5px 10px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 3px;
cursor: pointer;
font-size: 12px;
opacity: 0;
transition: opacity 0.3s ease;
z-index: 100;
}
.copy-vm-btn:hover {
background-color: #45a049;
}
/* pre标签容器样式 */
.pre-container {
position: relative;
}
/* 鼠标悬浮时显示按钮 */
.pre-container:hover .copy-vm-btn {
opacity: 1;
}
`;
const styleSheet = document.createElement("style");
styleSheet.textContent = buttonStyle;
document.head.appendChild(styleSheet);
// 设置页面的开关样式
const switchStyles = {
position: 'relative',
width: '50px',
height: '24px',
appearance: 'none',
outline: 'none',
borderRadius: '12px',
backgroundColor: '#ccc',
cursor: 'pointer',
verticalAlign: 'middle'
};
const sliderStyles = {
position: 'absolute',
top: '2px',
left: '2px',
width: '20px',
height: '20px',
borderRadius: '50%',
backgroundColor: '#fff',
transition: 'all 0.3s'
};
// -------------------------------------
// 注册脚本菜单
GM_registerMenuCommand("设置", showSettingsPopup);
// -------------------------------------
// 免责说明
window.addEventListener('load', function(event) {
if (!GM_getValue('mianzeshenming',false)){
// 如果检测到没有同意协议则渲染免责协议窗口
document.body.innerHTML = '';
const mzsf = document.createElement('div');
Object.assign(mzsf.style, {
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
padding: '20px',
backgroundColor: '#fff',
borderRadius: '8px',
boxShadow: '0 4px 8px rgba(0,0,0,0.2)',
zIndex: '1000',
width: '300px'
});
// 标题与提示渲染
const title = document.createElement('h2');
title.textContent = '免责协议';
mzsf.appendChild(title);
const tips = document.createElement('p');
tips.textContent = "请合理使用此脚本,造成一切损失与作者无关!同意协议后点击刷新进行页面刷新,如果不同意协议请删除此脚本并刷新网页"
tips.style.marginTop = '10px';
tips.style.marginBottom = '10px'
mzsf.appendChild(tips);
// 开关渲染
// 复制到虚拟机开关
mzsf.appendChild(createSwitch('同意免责协议', 'mianzeshenming'));
// 刷新按钮渲染
const sxButton = document.createElement('button');
sxButton.textContent = '刷新';
Object.assign(sxButton.style, {
marginTop: '15px',
padding: '8px 16px',
backgroundColor: '#f44336',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer'
});
sxButton.onclick = function() {
location.reload()
};
mzsf.appendChild(sxButton);
document.body.appendChild(mzsf);
}else {
// 否则渲染设置窗口
if (!GM_getValue("CopyToVM_Switch_Status",false) && !GM_getValue("Autoground_Switch_Status",false) && !GM_getValue("Select_Switch_Status",false) && !GM_getValue("NoOneShowsetting",false)) {
// 如果所有的配置项均未配置,则显示配置窗口
GM_setValue("NoOneShowsetting", true);
showSettingsPopup();
}
}
})
// -------------------------------------
// 函数部分
// 设置->创建开关 函数
function createSwitch(label, storageKey, onChange) {
const container = document.createElement('div');
container.style.marginBottom = '15px';
const switchLabel = document.createElement('label');
switchLabel.textContent = label;
switchLabel.style.marginRight = '10px';
switchLabel.style.fontWeight = 'normal';
const switchInput = document.createElement('input');
switchInput.type = 'checkbox';
Object.assign(switchInput.style, switchStyles);
const slider = document.createElement('span');
Object.assign(slider.style, sliderStyles);
switchInput.appendChild(slider);
// 初始状态
const isChecked = GM_getValue(storageKey, false);
switchInput.name = storageKey;
switchInput.checked = isChecked;
switchInput.style.backgroundColor = isChecked ? '#4CAF50' : '#ccc';
slider.style.transform = isChecked ? 'translateX(26px)' : 'translateX(0)';
// 事件处理
switchInput.addEventListener('change', function() {
const checked = this.checked;
this.style.backgroundColor = checked ? '#4CAF50' : '#ccc';
slider.style.transform = checked ? 'translateX(26px)' : 'translateX(0)';
GM_setValue(storageKey, checked);
if (onChange) onChange(checked);
});
container.appendChild(switchLabel);
container.appendChild(switchInput);
return container;
}
// 设置->主界面 函数
function showSettingsPopup() {
// 确保之前的弹窗被移除
const existingPopup = document.querySelector('div[style*="position: fixed; top: 50%; left: 50%;"]');
if (existingPopup) {
document.body.removeChild(existingPopup);
}
const popup = document.createElement('div');
Object.assign(popup.style, {
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
padding: '20px',
backgroundColor: '#fff',
borderRadius: '8px',
boxShadow: '0 4px 8px rgba(0,0,0,0.2)',
zIndex: '1000',
width: '300px'
});
// 标题与提示渲染
const title = document.createElement('h2');
title.textContent = '设置';
popup.appendChild(title);
const tip_list = ["启动立马生效,关闭刷新生效","复制到虚拟机优先级高于复制到实体机"];
const tips = document.createElement('p');
tips.textContent = tip_list[0];
tips.id = "setting_tip";
tips.style.marginTop = '10px';
tips.style.marginBottom = '10px'
popup.appendChild(tips);
let tip_id = 1
const tip_initer = setInterval(() => {
tip_id = tip_id==1 ? 0 : 1;
document.getElementById("setting_tip").innerHTML = tip_list[tip_id];
}, 1000)
// 开关渲染
// 复制到虚拟机开关
popup.appendChild(createSwitch('复制到虚拟机', 'CopyToVM_Switch_Status'));
// 实验报告滚动
popup.appendChild(createSwitch('实验报告自动滚动到底', 'Autoground_Switch_Status'));
// 移除复制限制
popup.appendChild(createSwitch('移除移除选择、复制、剪切操作的限制', 'Select_Switch_Status'));
// 复制到实体机开关
popup.appendChild(createSwitch('复制到实体机', 'CopyToTrue_Switch_Status'));
// 关闭按钮渲染
const closeButton = document.createElement('button');
closeButton.textContent = '关闭';
Object.assign(closeButton.style, {
marginTop: '15px',
padding: '8px 16px',
backgroundColor: '#f44336',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer'
});
closeButton.onclick = function() {
document.body.removeChild(popup);
clearInterval(tip_initer)
};
popup.appendChild(closeButton);
document.body.appendChild(popup);
}
// 主功能->弹窗函数
function notification(text) {
const notification = document.createElement('div');
notification.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
padding: 10px 20px;
background-color: #4CAF50;
color: white;
border-radius: 5px;
z-index: 10000;
`;
notification.textContent = text;
document.body.appendChild(notification);
setTimeout(() => notification.remove(), 2000);
}
// 复制到虚拟机功能 -> 复制到虚拟机 函数
function sendToVirtualMachine(text) {
if (GM_getValue("CopyToVM_Switch_Status",false)){
console.log("text"+text)
const code = "code:"+text
document.getElementById("tool_content").contentWindow.postMessage(code, "*");
}else if (GM_getValue("CopyToTrue_Switch_Status",false)) {
mycopy(text);
}
return true
}
// 复制到实体机功能 -> 复制到实体机 函数
function mycopy(data) {
const TEXT_PLAIN = "text/plain";
const TEXT_HTML = "text/html";
const COPY = "copy";
const opt = Object.prototype.toString;
const execCopyCommand = (data) => {
const textarea = document.createElement("textarea");
const handler = (event) => {
event.preventDefault();
event.stopImmediatePropagation();
for (const [key, value] of Object.entries(data)) {
event.clipboardData && event.clipboardData.setData(key, value);
}
};
textarea.addEventListener(COPY, handler, true);
textarea.style.position = "fixed";
textarea.style.left = "-999999999px";
textarea.style.top = "-999999999px";
textarea.value = data[TEXT_PLAIN] || " ";
document.body.appendChild(textarea);
textarea.select();
document.execCommand("copy");
textarea.removeEventListener(COPY, handler);
document.body.removeChild(textarea);
}
function isString(value) {
return opt.call(value) === "[object String]";
}
const isEmptyContent = (data) => {
if (!data)
return true;
return isString(data) ? !data : !data[TEXT_PLAIN];
};
const params = isString(data) ? { [TEXT_PLAIN]: data } : data;
const plainText = params[TEXT_PLAIN];
if (!plainText)
return false;
if (navigator.clipboard && window.ClipboardItem) {
const dataItems = {};
for (const [key, value] of Object.entries(params)) {
const blob = new Blob([value], { type: key });
dataItems[key] = blob;
}
navigator.clipboard.write([new ClipboardItem(dataItems)]).catch(() => {
execCopyCommand(params);
});
} else {
execCopyCommand(params);
}
return true;
}
// -------------------------------------
// 定时器部分
// 页面加载时移除选择、复制、剪切操作的限制
setInterval(() => {
if (GM_getValue("Select_Switch_Status",false)) {
document.onselectstart = function(event) {return true;};
document.oncopy = function(event) {return true;};
document.oncut = function(event) {return true;};
var elements = document.querySelectorAll('[class^=" language-"]');
elements.forEach(function(element) {element.style.cssText = '';});
}
}, 1000)
// 复制到虚拟/虚拟机按钮渲染
setInterval(() => {
if (GM_getValue("CopyToVM_Switch_Status",false)||GM_getValue("CopyToTrue_Switch_Status",false)){
const btn_type = GM_getValue("CopyToVM_Switch_Status") ? ["虚拟",'Vm'] : ["实体","Tr"];
document.querySelectorAll('pre[class^=" language-"]').forEach(pre => {
// 元素存在且状态正确
if (pre.getAttribute('data-type-button')==btn_type[1]) return;
// 元素存在且状态不正确
if (pre.getAttribute('data-type-button') != null && pre.getAttribute('data-type-button')!=btn_type[1]) {
pre.setAttribute('data-type-button', btn_type[1]);
const btns = document.getElementsByClassName('copy-vm-btn')
Array.from(btns).forEach(btn=>{
btn.innerHTML = `复制到${btn_type[0]}`;
btn.onclick = function() {
const success = sendToVirtualMachine(pre.textContent);
if (success) {notification(`已复制到${btn_type[0]}机!`);}
};
})
return
};
// 元素不存在
console.log("不正确")
const container = document.createElement('div');
container.className = 'pre-container';
pre.parentNode.insertBefore(container, pre);
container.appendChild(pre);
const button = document.createElement('button');
button.className = 'copy-vm-btn';
pre.setAttribute('data-type-button', btn_type[1]);
button.textContent = `复制到${btn_type[0]}`
button.onclick = function() {
const success = sendToVirtualMachine(pre.textContent);
if (success) {notification(`已复制到${btn_type[0]}机!`);}
};
container.appendChild(button);
});
}
}, 1000);
// 点击实验报告滚动到最下面
setInterval(() => {
if (GM_getValue("Autoground_Switch_Status",false)) {
try {
document.querySelector("#assignment-report").addEventListener('click', function() {
const lastElement =document.getElementById("report_area_ifr").contentDocument.querySelector("#tinymce p:last-child")
if (lastElement) {
lastElement.scrollIntoView({
behavior: 'smooth',
block: 'center',
inline: 'nearest'
});
}
});
}catch {}
}
}, 1000)
})();