明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 1076|回复: 15

[经验] 明经复制/下载代码篡改猴扩展

  [复制链接]
发表于 2025-10-31 09:32:28 | 显示全部楼层 |阅读模式
本帖最后由 yangyangyixia 于 2025-11-3 10:28 编辑

原贴:http://bbs.mjtd.com/thread-193463-1-1.html

增加了一个下载按钮,直接下载为:代码.lsp


有缺陷,部分代码复制错误,我再研究研究……
修改了一下,不会漏掉代码了。
还是不太完美:下载下来的lsp文件,如果代码中有中文,格式会自动保存为utf8编码,需要手动改为ansi编码,这个我不会优化了

  1. // ==UserScript==
  2. // @name         明经复制/下载代码扩展
  3. // @namespace    http://tampermonkey.net/
  4. // @version      2025.10.31.1
  5. // @description  复制明经论坛代码区的代码并支持下载为.lsp文件
  6. // @author       edata yangyangyixia
  7. // @match        *://*.mjtd.com/*
  8. // @icon         http://bbs.mjtd.com/favicon.ico
  9. // @grant        none
  10. // ==/UserScript==

  11. (function() {
  12.     'use strict';

  13.     // 复制到剪贴板函数
  14.     function copyToClipboard(text) {
  15.         return new Promise((resolve, reject) => {
  16.             if (navigator.clipboard) {
  17.                 navigator.clipboard.writeText(text).then(resolve).catch(reject);
  18.             } else {
  19.                 // 兼容旧版浏览器的备用方法
  20.                 const textarea = document.createElement('textarea');
  21.                 textarea.value = text;
  22.                 textarea.style.position = 'fixed';
  23.                 textarea.style.opacity = '0';
  24.                 document.body.appendChild(textarea);
  25.                 textarea.select();

  26.                 try {
  27.                     const successful = document.execCommand('copy');
  28.                     document.body.removeChild(textarea);
  29.                     successful ? resolve() : reject(new Error('复制失败'));
  30.                 } catch (err) {
  31.                     document.body.removeChild(textarea);
  32.                     reject(err);
  33.                 }
  34.             }
  35.         });
  36.     }

  37.     // 下载文件函数
  38.     function downloadFile(filename, content) {
  39.         const blob = new Blob([content], { type: 'text/plain;charset=utf-8' });
  40.         const url = URL.createObjectURL(blob);
  41.         const link = document.createElement('a');

  42.         link.href = url;
  43.         link.download = filename;
  44.         link.style.display = 'none';

  45.         document.body.appendChild(link);
  46.         link.click();
  47.         document.body.removeChild(link);

  48.         // 清理URL对象
  49.         setTimeout(() => URL.revokeObjectURL(url), 100);
  50.     }

  51.     // 转换html转义字符为正常字符
  52.     function unescapeHTML(str) {
  53.         if (!str) return '';
  54.         const entities = {
  55.             'nbsp': ' ',
  56.             'lt': '<',
  57.             'gt': '>',
  58.             'amp': '&',
  59.             'quot': '"',
  60.             '#39': "'",
  61.             '#60': '<',
  62.             '#62': '>',
  63.             '#32': ' ',
  64.             '#160': ' '
  65.         };
  66.         return str.replace(/&([^;]+);/g, function(match, entity) {
  67.             if (entity in entities) {
  68.                 return entities[entity];
  69.             }
  70.             // 处理数字实体如 < >   等
  71.             if (entity.startsWith('#')) {
  72.                 const code = entity.substring(1);
  73.                 return String.fromCharCode(parseInt(code));
  74.             }
  75.             return match;
  76.         });
  77.     }

  78.     // 安全地移除HTML标签(保留代码中的 < > 符号)
  79.     function removeTags(str) {
  80.         if (!str) return '';

  81.         // 先解码所有HTML实体
  82.         let decoded = unescapeHTML(str);

  83.         // 只移除真正的HTML标签,保留代码中的 < 和 > 符号
  84.         // 匹配以 < 开头,后跟字母或/,然后以 > 结尾的标签
  85.         return decoded.replace(/<\/?[a-z][\s\S]*?>/gi, "");
  86.     }

  87.     // 移除换行<br />标记
  88.     function removeBrTags(str) {
  89.         if (!str) return '';
  90.         return str.toString().replace(/<br\s*\/?>/gi, "\n");
  91.     }

  92.     // 清理和格式化代码文本(复制和下载使用相同的格式化函数)
  93.     function formatCodeText(text) {
  94.         if (!text) return '';

  95.         // 先解码HTML实体(包括 < > & nbsp 等)
  96.         let formatted = text;

  97.         // 多次解码,确保所有HTML实体都被处理
  98.         let previous = '';
  99.         while (formatted !== previous) {
  100.             previous = formatted;
  101.             formatted = unescapeHTML(formatted);
  102.         }

  103.         // 将<br>标签转换为换行符
  104.         formatted = removeBrTags(formatted);

  105.         // 移除其他HTML标签(但保留代码中的 < > 符号)
  106.         formatted = removeTags(formatted);

  107.         // 彻底处理所有nbsp和不间断空格,但保留原始空格结构
  108.         // 只替换nbsp相关实体,不修改普通空格
  109.         formatted = formatted.replace(/ /g, ' ');
  110.         formatted = formatted.replace(/\u00A0/g, ' ');
  111.         formatted = formatted.replace(/ /g, ' ');
  112.         formatted = formatted.replace(/ /g, ' ');

  113.         // 清理多余的空行(但保留代码缩进)
  114.         formatted = formatted.replace(/\n\s*\n/g, '\n').trim();

  115.         return formatted;
  116.     }

  117.     // 添加样式
  118.     function addStyles() {
  119.         const style = document.createElement('style');
  120.         style.textContent = `
  121.             .copy-btn, .download-btn {
  122.                 display: inline-block;
  123.                 margin-left: 10px;
  124.                 padding: 2px 8px;
  125.                 border-radius: 3px;
  126.                 font-size: 12px;
  127.                 cursor: pointer;
  128.                 transition: background 0.3s;
  129.                 border: none;
  130.                 font-family: inherit;
  131.             }
  132.             .copy-btn {
  133.                 background: #4CAF50;
  134.                 color: white;
  135.             }
  136.             .copy-btn:hover {
  137.                 background: #45a049;
  138.             }
  139.             .copy-btn:active {
  140.                 background: #3d8b40;
  141.             }
  142.             .copy-btn.copied {
  143.                 background: #2196F3;
  144.             }
  145.             .download-btn {
  146.                 background: #ff9800;
  147.                 color: white;
  148.             }
  149.             .download-btn:hover {
  150.                 background: #f57c00;
  151.             }
  152.             .download-btn:active {
  153.                 background: #ef6c00;
  154.             }
  155.             .download-btn.downloaded {
  156.                 background: #9c27b0;
  157.             }
  158.             .code-buttons {
  159.                 display: inline-block;
  160.                 margin-left: 10px;
  161.             }
  162.         `;
  163.         document.head.appendChild(style);
  164.     }

  165.     // 获取代码内容
  166.     function getCodeContent(element) {
  167.         const textarea = element.querySelector('textarea');
  168.         if (textarea) {
  169.             // 对于textarea,优先使用value,如果没有则用innerHTML
  170.             return textarea.value || textarea.innerHTML;
  171.         }

  172.         const codeContent = element.querySelector('.jssccodecontent');
  173.         if (codeContent) {
  174.             return codeContent.innerHTML || codeContent.textContent || codeContent.innerText;
  175.         }

  176.         return '';
  177.     }

  178.     // 处理复制操作
  179.     async function handleCopy(element, copyBtn) {
  180.         const rawText = getCodeContent(element);
  181.         const formattedText = formatCodeText(rawText);

  182.         try {
  183.             if (typeof setCopy === 'function') {
  184.                 setCopy(formattedText, "代码已复制到剪贴板");
  185.             } else {
  186.                 await copyToClipboard(formattedText);
  187.                 setCopy(formattedText, "代码已复制到剪贴板");
  188.             }

  189.             copyBtn.textContent = '复制成功!';
  190.             copyBtn.classList.add('copied');
  191.             setTimeout(() => {
  192.                 copyBtn.textContent = '格式复制';
  193.                 copyBtn.classList.remove('copied');
  194.             }, 2000);

  195.         } catch (err) {
  196.             console.error('复制失败:', err);
  197.             copyBtn.textContent = '复制失败';
  198.             setTimeout(() => {
  199.                 copyBtn.textContent = '格式复制';
  200.             }, 2000);
  201.         }
  202.     }

  203.     // 处理下载操作
  204.     function handleDownload(element, downloadBtn) {
  205.         const rawText = getCodeContent(element);
  206.         // 使用与复制相同的格式化函数,确保格式一致
  207.         const formattedText = formatCodeText(rawText);

  208.         if (!formattedText.trim()) {
  209.             setCopy(formattedText, "没有可下载的代码内容");
  210.             return;
  211.         }

  212.         const filename = `代码.lsp`;
  213.         downloadFile(filename, formattedText);

  214.         downloadBtn.textContent = '下载成功!';
  215.         downloadBtn.classList.add('downloaded');
  216.         setCopy(formattedText, "已下载为代码.lsp");
  217.         setTimeout(() => {
  218.             downloadBtn.textContent = '下载lsp';
  219.             downloadBtn.classList.remove('downloaded');
  220.         }, 2000);
  221.     }

  222.     // 主处理函数 - 添加复制和下载按钮
  223.     function addCodeButtons() {
  224.         // 获取所有以"mc_code"开头的元素
  225.         const elements = [];
  226.         let index = 0;

  227.         while (true) {
  228.             const element = document.getElementById(`mc_code${index}`);
  229.             if (!element) break;
  230.             elements.push(element);
  231.             index++;
  232.         }

  233.         // 处理每个找到的元素
  234.         elements.forEach(element => {
  235.             const titleElement = element.querySelector('.jssccodetitle');
  236.             if (!titleElement) return;

  237.             // 检查是否已添加按钮容器
  238.             let buttonsContainer = titleElement.querySelector('.code-buttons');
  239.             if (buttonsContainer) return;

  240.             // 创建按钮容器
  241.             buttonsContainer = document.createElement('span');
  242.             buttonsContainer.className = 'code-buttons';

  243.             // 创建复制按钮
  244.             const copyBtn = document.createElement('button');
  245.             copyBtn.className = 'copy-btn';
  246.             copyBtn.textContent = '格式复制';
  247.             copyBtn.title = '点击复制格式化后的代码';

  248.             // 创建下载按钮
  249.             const downloadBtn = document.createElement('button');
  250.             downloadBtn.className = 'download-btn';
  251.             downloadBtn.textContent = '下载.lsp';
  252.             downloadBtn.title = '点击下载为.lsp文件';

  253.             // 添加点击事件
  254.             copyBtn.addEventListener('click', () => handleCopy(element, copyBtn));
  255.             downloadBtn.addEventListener('click', () => handleDownload(element, downloadBtn));

  256.             // 插入按钮
  257.             buttonsContainer.appendChild(copyBtn);
  258.             buttonsContainer.appendChild(downloadBtn);
  259.             titleElement.appendChild(buttonsContainer);
  260.         });
  261.     }

  262.     // 初始化函数
  263.     function init() {
  264.         addStyles();
  265.         addCodeButtons();

  266.         // 监听DOM变化,动态添加按钮
  267.         const observer = new MutationObserver(() => {
  268.             addCodeButtons();
  269.         });

  270.         observer.observe(document.body, {
  271.             childList: true,
  272.             subtree: true
  273.         });

  274.         // 页面加载完成后再次检查
  275.         window.addEventListener('load', addCodeButtons);
  276.     }

  277.     // 延迟初始化,确保页面加载完成
  278.     if (document.readyState === 'loading') {
  279.         document.addEventListener('DOMContentLoaded', init);
  280.     } else {
  281.         init();
  282.     }
  283. })();






本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x

评分

参与人数 2明经币 +2 收起 理由
ptime + 1 很给力!
maiko + 1 很给力!

查看全部评分

"觉得好,就打赏"
还没有人打赏,支持一下
回复

使用道具 举报

发表于 2025-10-31 12:29:58 | 显示全部楼层
这个更加高级了
回复 支持 0 反对 1

使用道具 举报

发表于 2025-10-31 10:58:25 | 显示全部楼层
这个更好                                 
回复 支持 反对

使用道具 举报

发表于 2025-10-31 12:56:36 | 显示全部楼层
点击格式复制,直接复制到篡改猴里面会有一处格式有问题的地方,不知道什么原因,如果直接从下到上手选复制就没有这个问题了



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x
回复 支持 反对

使用道具 举报

发表于 2025-10-31 10:00:35 | 显示全部楼层

感谢,好用

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x
回复 支持 反对

使用道具 举报

发表于 2025-10-31 11:05:27 | 显示全部楼层
更高级了 可以下载为lsp了
回复 支持 反对

使用道具 举报

发表于 2025-10-31 11:34:46 来自手机 | 显示全部楼层
这个更加高级了
回复 支持 反对

使用道具 举报

发表于 2025-10-31 12:14:37 | 显示全部楼层
这个可以,很实用
回复 支持 反对

使用道具 举报

发表于 2025-10-31 12:29:25 | 显示全部楼层
这个太给力了
回复 支持 反对

使用道具 举报

发表于 2025-10-31 13:42:26 | 显示全部楼层
测试了这个http://bbs.mjtd.com/thread-193886-1-1.html,会缺括号
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2025-11-28 11:39 , Processed in 0.238254 second(s), 29 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表