diff --git a/LMSGuides助手-源码.user.js b/LMSGuides助手-源码.user.js new file mode 100755 index 0000000..4b9a1c6 --- /dev/null +++ b/LMSGuides助手-源码.user.js @@ -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) +})(); \ No newline at end of file