CSDN优化

支持手机端和PC端,屏蔽广告,优化浏览体验,自动跳转拦截的URL

当前为 2024-04-25 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name CSDN优化
  3. // @icon https://www.csdn.net/favicon.ico
  4. // @namespace https://greasyfork.org/zh-CN/scripts/406136
  5. // @supportURL https://github.com/WhiteSevs/TamperMonkeyScript/issues
  6. // @version 2024.4.25
  7. // @license MIT
  8. // @description 支持手机端和PC端,屏蔽广告,优化浏览体验,自动跳转拦截的URL
  9. // @author WhiteSevs
  10. // @match *://*.csdn.net/*
  11. // @grant GM_registerMenuCommand
  12. // @grant GM_unregisterMenuCommand
  13. // @grant GM_getValue
  14. // @grant GM_setValue
  15. // @grant GM_deleteValue
  16. // @grant GM_info
  17. // @grant unsafeWindow
  18. // @run-at document-start
  19. // @require https://update.greasyfork.org/scripts/462234/1322684/Message.js
  20. // @require https://update.greasyfork.org/scripts/456485/1360571/pops.js
  21. // @require https://update.greasyfork.org/scripts/455186/1365298/WhiteSevsUtils.js
  22. // @require https://update.greasyfork.org/scripts/465772/1360574/DOMUtils.js
  23. // ==/UserScript==
  24.  
  25. (function () {
  26. if (typeof unsafeWindow === "undefined") {
  27. unsafeWindow = globalThis || window;
  28. }
  29. /**
  30. * @type {import("../库/pops")}
  31. */
  32. const pops = window.pops;
  33. /**
  34. * @type {import("../库/Utils")}
  35. */
  36. const utils = window.Utils.noConflict();
  37. /**
  38. * @type {import("../库/DOMUtils")}
  39. */
  40. const DOMUtils = window.DOMUtils.noConflict();
  41. /**
  42. * @type {import("../库/Qmsg")}
  43. */
  44. const Qmsg = window.Qmsg;
  45.  
  46. const log = new utils.Log(GM_info, unsafeWindow.console || console);
  47. log.config({
  48. autoClearConsole: false,
  49. });
  50.  
  51. const GM_addStyle = utils.addStyle;
  52.  
  53. /**
  54. * 油猴菜单
  55. */
  56. const GM_Menu = new utils.GM_Menu({
  57. GM_getValue,
  58. GM_setValue,
  59. GM_registerMenuCommand,
  60. GM_unregisterMenuCommand,
  61. });
  62.  
  63. /* 配置吐司Qmsg */
  64. Qmsg.config({
  65. position: "top",
  66. html: true,
  67. maxNums: 5,
  68. autoClose: true,
  69. showClose: false,
  70. showReverse: true,
  71. });
  72.  
  73. /**
  74. * 移除元素(未出现也可以等待出现)
  75. * @param {string} selectorText 元素选择器
  76. */
  77. const waitForElementToRemove = function (selectorText = "") {
  78. utils.waitNodeList(selectorText).then((nodeList) => {
  79. nodeList.forEach((item) => {
  80. item.remove();
  81. });
  82. });
  83. };
  84.  
  85. const CSDN = {
  86. blog: {
  87. /**
  88. * 判断是否是博客
  89. */
  90. isBlogRouter() {
  91. return Boolean(/blog.csdn.net/i.test(window.location.origin));
  92. },
  93. PC: {
  94. /**
  95. * 初始化
  96. */
  97. init() {
  98. this.addCSS();
  99. if (PopsPanel.getValue("CSDNAutoJumpRedirect_PC")) {
  100. CSDN.blog.PC.jumpRedirect();
  101. }
  102. if (PopsPanel.getValue("csdn_pc_cknow")) {
  103. this.cKnow();
  104. }
  105. if (PopsPanel.getValue("articleCenter")) {
  106. this.articleCenter();
  107. }
  108. if (PopsPanel.getValue("shieldLoginDialog")) {
  109. this.shieldLoginDialog();
  110. }
  111. if (PopsPanel.getValue("autoExpandContent")) {
  112. this.autoExpandContent();
  113. }
  114. PopsPanel.execMenu("csdnPC_blockComment", () => {
  115. this.blockComment();
  116. });
  117. if (PopsPanel.getValue("csdnShieldfloatingButton")) {
  118. this.shieldRightToolbar();
  119. }
  120. if (PopsPanel.getValue("csdnShieldBottomRecommendArticle")) {
  121. this.csdnShieldBottomRecommendArticle();
  122. }
  123. if (PopsPanel.getValue("csdnShieldBottomSkillTree")) {
  124. this.csdnShieldBottomSkillTree();
  125. }
  126. if (PopsPanel.getValue("csdnShieldBottomFloatingToolbar")) {
  127. this.csdnShieldBottomFloatingToolbar();
  128. }
  129. if (PopsPanel.getValue("csdn_pc_shieldLeftBlogContainerAside")) {
  130. this.shieldLeftBlogContainerAside();
  131. }
  132. if (PopsPanel.getValue("csdn_pc_shieldRightDirectoryInformation")) {
  133. this.shieldRightDirectoryInformation();
  134. }
  135. if (PopsPanel.getValue("csdn_pc_shieldTopToolbar")) {
  136. this.shieldTopToolbar();
  137. }
  138. if (PopsPanel.getValue("csdn_pc_shieldArticleSearchTip")) {
  139. this.shieldArticleSearchTip();
  140. }
  141. this.initRightToolbarOffset();
  142. DOMUtils.ready(() => {
  143. if (PopsPanel.getValue("csdn_pc_removeClipboardHijacking")) {
  144. this.removeClipboardHijacking();
  145. }
  146. if (PopsPanel.getValue("csdn_pc_unBlockCopy")) {
  147. this.unBlockCopy();
  148. }
  149. if (PopsPanel.getValue("csdn_pc_identityCSDNDownload")) {
  150. this.identityCSDNDownload();
  151. }
  152. if (PopsPanel.getValue("csdn_pc_clickPreCodeAutomatically")) {
  153. this.clickPreCodeAutomatically();
  154. }
  155. if (PopsPanel.getValue("autoExpandContent")) {
  156. this.clickPreCodeAutomatically();
  157. }
  158. if (PopsPanel.getValue("csdn_pc_restoreComments")) {
  159. this.restoreComments();
  160. }
  161. if (PopsPanel.getValue("csdn_pc_addGotoRecommandButton")) {
  162. this.addGotoRecommandButton();
  163. }
  164. });
  165. if (window.location.hostname === "wenku.csdn.net") {
  166. this.addWenKuCSS();
  167. }
  168. },
  169. getDefaultShieldCSS() {
  170. return `
  171. .ecommend-item-box.recommend-recommend-box,
  172. .login-mark,
  173. .opt-box.text-center,
  174. .leftPop,
  175. #csdn-shop-window,
  176. .toolbar-advert,
  177. .hide-article-box,
  178. .user-desc.user-desc-fix,
  179. .recommend-card-box,
  180. .more-article,
  181. .article-show-more,
  182. #csdn-toolbar-profile-nologin,
  183. .guide-rr-first,
  184. #recommend-item-box-tow,
  185. /* 发文章得原力分图片提示 */
  186. div.csdn-toolbar-creative-mp,
  187. /* 阅读终点,创作起航,您可以撰写心得或摘录文章要点写篇博文。 */
  188. #toolBarBox div.write-guide-buttom-box,
  189. /* 觉得还不错? 一键收藏 */
  190. ul.toolbox-list div.tool-active-list,
  191. /* 右边按钮组的最上面的创作话题 */
  192. div.csdn-side-toolbar .activity-swiper-box,
  193. .sidetool-writeguide-box .tip-box,
  194. /* 右下角的登录提示 */
  195. .passport-login-tip-container{
  196. display: none !important;
  197. }`;
  198. },
  199. addCSS() {
  200. let shieldCSS = PopsPanel.getValue(
  201. "csdn-pc-css",
  202. this.getDefaultShieldCSS()
  203. );
  204. GM_addStyle(shieldCSS);
  205. GM_addStyle(`
  206. /* 自动展开代码块 */
  207. .comment-list-box,
  208. main div.blog-content-box pre{
  209. max-height: none !important;
  210. }
  211. /* 自动展开全文 */
  212. #article_content,
  213. .user-article.user-article-hide{
  214. height: auto !important;
  215. overflow: auto !important;
  216. }
  217. .blog_container_aside,
  218. #nav{
  219. margin-left: -45px;
  220. }
  221. .recommend-right.align-items-stretch.clearfix,.dl_right_fixed{
  222. margin-left: 45px;
  223. }
  224. #content_views,
  225. #content_views pre,
  226. #content_views pre code{
  227. user-select: text !important;
  228. }
  229. `);
  230. },
  231. /**
  232. * 添加在wenku.csdn.net下的CSS
  233. */
  234. addWenKuCSS() {
  235. GM_addStyle(`
  236. /* wenku顶部横幅 */
  237. #app > div > div.main.pb-32 > div > div.top-bar,
  238. /* 底部展开全文 */
  239. #chatgpt-article-detail > div.layout-center > div.main > div.article-box > div.cont.first-show.forbid > div.open{
  240. display: none !important;
  241. }
  242. #chatgpt-article-detail > div.layout-center > div.main > div.article-box > div.cont.first-show.forbid{
  243. max-height: unset !important;
  244. height: auto !important;
  245. overflow: auto !important;
  246. }
  247. `);
  248. GM_addStyle(`
  249. .forbid{
  250. user-select: text !important;
  251. }
  252. `);
  253. },
  254. /**
  255. * 去除剪贴板劫持
  256. */
  257. removeClipboardHijacking() {
  258. log.info("去除剪贴板劫持");
  259. document.querySelector(".article-copyright")?.remove();
  260. if (unsafeWindow.articleType) {
  261. unsafeWindow.articleType = 0;
  262. }
  263. if (
  264. unsafeWindow.csdn &&
  265. unsafeWindow.csdn.copyright &&
  266. unsafeWindow.csdn.copyright.textData
  267. ) {
  268. unsafeWindow.csdn.copyright.textData = "";
  269. }
  270. if (
  271. unsafeWindow.csdn &&
  272. unsafeWindow.csdn.copyright &&
  273. unsafeWindow.csdn.copyright.htmlData
  274. ) {
  275. unsafeWindow.csdn.copyright.htmlData = "";
  276. }
  277. },
  278. /**
  279. * 取消禁止复制
  280. */
  281. unBlockCopy() {
  282. log.info("取消禁止复制");
  283. document.addEventListener(
  284. "click",
  285. function (event) {
  286. let target = event.target;
  287. if (!target.classList.contains("hljs-button")) {
  288. return;
  289. }
  290. utils.preventEvent(event);
  291. /* 需要复制的文本 */
  292. let copyText =
  293. target.parentElement.innerText ||
  294. target.parentElement.textContent;
  295. utils.setClip(copyText);
  296. log.success("点击复制 复制成功~");
  297. target.setAttribute("data-title", "复制成功");
  298. },
  299. {
  300. capture: true,
  301. }
  302. );
  303. let changeDataTitle = new utils.LockFunction(function (event) {
  304. let target = event.target;
  305. if (!target.localName === "pre") {
  306. return;
  307. }
  308. target
  309. .querySelector(".hljs-button")
  310. ?.setAttribute("data-title", "复制");
  311. });
  312.  
  313. document.addEventListener("mouseenter", changeDataTitle.run, {
  314. capture: true,
  315. });
  316. document.addEventListener("mouseleave", changeDataTitle.run, {
  317. capture: true,
  318. });
  319. /* 取消Ctrl+C的禁止 */
  320. utils.waitNode("#content_views").then((element) => {
  321. unsafeWindow?.$("#content_views")?.unbind("copy");
  322. element.addEventListener("copy", function (event) {
  323. utils.preventEvent(event);
  324. utils.setClip(unsafeWindow.getSelection().toString());
  325. log.success("Ctrl+C 复制成功~");
  326. return false;
  327. });
  328. });
  329. /* 删除所有复制按钮的原有的复制事件 */
  330. utils.waitNode(".hljs-button").then(() => {
  331. setTimeout(() => {
  332. document.querySelectorAll(".hljs-button").forEach((element) => {
  333. element.removeAttribute("onclick");
  334. element.removeAttribute("data-report-click");
  335. element.setAttribute("data-title", "复制");
  336. });
  337. }, 250);
  338. });
  339. },
  340. /**
  341. * 点击代码块自动展开
  342. */
  343. clickPreCodeAutomatically() {
  344. log.info("点击代码块自动展开");
  345. document.addEventListener("click", function (event) {
  346. let target = event.target;
  347. if (target.localName !== "pre") {
  348. return;
  349. }
  350. target.style.setProperty("height", "auto");
  351. target.querySelector(".hide-preCode-box")?.remove();
  352. });
  353. },
  354. /**
  355. * 恢复评论到正确位置
  356. */
  357. restoreComments() {
  358. /* 第一条评论 */
  359. log.info("恢复评论到正确位置-第一条评论");
  360. utils.waitNode(".first-recommend-box").then((element) => {
  361. let recommendBoxElement = document.querySelector(
  362. ".recommend-box.insert-baidu-box.recommend-box-style"
  363. );
  364. recommendBoxElement.insertBefore(
  365. element,
  366. recommendBoxElement.firstChild
  367. );
  368. });
  369. log.info("恢复评论到正确位置-第二条评论");
  370. /* 第二条评论 */
  371. utils.waitNode(".second-recommend-box").then((element) => {
  372. let recommendBoxElement = document.querySelector(
  373. ".recommend-box.insert-baidu-box.recommend-box-style"
  374. );
  375. recommendBoxElement.insertBefore(
  376. element,
  377. recommendBoxElement.firstChild
  378. );
  379. });
  380. },
  381. /**
  382. * 标识CSDN下载的链接
  383. */
  384. identityCSDNDownload() {
  385. log.info("标识CSDN下载的链接");
  386. document
  387. .querySelectorAll(
  388. ".recommend-item-box[data-url*='https://download.csdn.net/']"
  389. )
  390. .forEach((item) => {
  391. if (PopsPanel.getValue("removeCSDNDownloadPC")) {
  392. item.remove();
  393. } else {
  394. item
  395. .querySelector(".content-box")
  396. .style.setProperty("border", "2px solid red");
  397. }
  398. });
  399. },
  400. /**
  401. * 全文居中
  402. */
  403. articleCenter() {
  404. log.info("全文居中");
  405. GM_addStyle(`
  406. #mainBox main{
  407. width: inherit !important;
  408. }
  409. `);
  410. GM_addStyle(`
  411. @media (min-width: 1320px) and (max-width:1380px) {
  412. .nodata .container {
  413. width: 900px !important
  414. }
  415. .nodata .container main {
  416. width: 900px
  417. }
  418. .nodata .container main #pcCommentBox pre >ol.hljs-ln {
  419. width: 490px !important
  420. }
  421. .nodata .container main .articleConDownSource {
  422. width: 500px
  423. }
  424. }
  425. @media screen and (max-width: 1320px) {
  426. .nodata .container {
  427. width: 760px !important
  428. }
  429. .nodata .container main {
  430. width: 760px
  431. }
  432. .nodata .container main #pcCommentBox pre >ol.hljs-ln {
  433. width: 490px !important
  434. }
  435. .nodata .container main .toolbox-list .tool-reward {
  436. display: none
  437. }
  438. .nodata .container main .more-toolbox-new .toolbox-left .profile-box .profile-name {
  439. max-width: 128px
  440. }
  441. .nodata .container main .articleConDownSource {
  442. width: 420px
  443. }
  444. }
  445. @media screen and (min-width: 1380px) {
  446. .nodata .container {
  447. width: 1010px !important
  448. }
  449. .nodata .container main {
  450. width: 1010px
  451. }
  452. .nodata .container main #pcCommentBox pre >ol.hljs-ln {
  453. width: 490px !important
  454. }
  455. .nodata .container main .articleConDownSource {
  456. width: 560px
  457. }
  458. }
  459. @media (min-width: 1550px) and (max-width:1700px) {
  460. .nodata .container {
  461. width: 820px !important
  462. }
  463. .nodata .container main {
  464. width: 820px
  465. }
  466. .nodata .container main #pcCommentBox pre >ol.hljs-ln {
  467. width: 690px !important
  468. }
  469. .nodata .container main .articleConDownSource {
  470. width: 500px
  471. }
  472. }
  473. @media screen and (min-width: 1700px) {
  474. .nodata .container {
  475. width: 1010px !important
  476. }
  477. .nodata .container main {
  478. width: 1010px
  479. }
  480. .nodata .container main #pcCommentBox pre >ol.hljs-ln {
  481. width: 690px !important
  482. }
  483. .nodata .container main .articleConDownSource {
  484. width: 560px
  485. }
  486. }
  487. `);
  488. },
  489. /**
  490. * 添加前往评论的按钮,在返回顶部的下面
  491. */
  492. addGotoRecommandButton() {
  493. log.info("添加前往评论的按钮,在返回顶部的上面");
  494. let gotoRecommandNode = document.createElement("a");
  495. gotoRecommandNode.className = "option-box";
  496. gotoRecommandNode.setAttribute("data-type", "gorecommand");
  497. gotoRecommandNode.innerHTML = `<span class="show-txt" style="display:flex;opacity:100;">前往<br>评论</span>`;
  498. gotoRecommandNode.addEventListener("click", function () {
  499. let toolbarBoxElement = document.querySelector("#toolBarBox");
  500. if (!toolbarBoxElement.getClientRects().length) {
  501. log.error("评论区处于隐藏状态");
  502. return;
  503. }
  504. log.info("滚动到评论");
  505. let toolbarBoxOffsetTop =
  506. toolbarBoxElement.getBoundingClientRect().top + window.scrollY;
  507. let csdnToolBarElement = document.querySelector("#csdn-toolbar");
  508. let csdnToolBarStyles = window.getComputedStyle(csdnToolBarElement);
  509. let csdnToolBarHeight =
  510. csdnToolBarElement.clientHeight -
  511. parseFloat(csdnToolBarStyles.paddingTop) -
  512. parseFloat(csdnToolBarStyles.paddingBottom);
  513. window.scrollTo({
  514. top: toolbarBoxOffsetTop - csdnToolBarHeight - 8,
  515. left: 0,
  516. behavior: "smooth",
  517. });
  518. });
  519. utils.waitNode(".csdn-side-toolbar").then(() => {
  520. let targetElement = document.querySelector(
  521. ".csdn-side-toolbar a:nth-last-child(2)"
  522. );
  523. targetElement.parentElement.insertBefore(
  524. gotoRecommandNode,
  525. targetElement.nextSibling
  526. );
  527. });
  528. },
  529. /**
  530. * 屏蔽登录弹窗
  531. */
  532. shieldLoginDialog() {
  533. log.info("屏蔽登录弹窗");
  534. GM_addStyle(`.passport-login-container{display: none !important;}`);
  535. },
  536. /**
  537. * 自动展开内容块
  538. */
  539. autoExpandContent() {
  540. log.info("自动展开内容块");
  541. GM_addStyle(`
  542. pre.set-code-hide{height: auto !important;}
  543. pre.set-code-hide .hide-preCode-box{display: none !important;}
  544. `);
  545. },
  546. /**
  547. * 屏蔽右侧工具栏
  548. */
  549. shieldRightToolbar() {
  550. log.info("屏蔽右侧工具栏");
  551. GM_addStyle(`div.csdn-side-toolbar{display: none !important;}`);
  552. },
  553. /**
  554. * 屏蔽评论区
  555. */
  556. blockComment() {
  557. log.info("屏蔽评论区");
  558. GM_addStyle(`#pcCommentBox{display: none !important;}`);
  559. },
  560. /**
  561. * 屏蔽底部推荐文章
  562. */
  563. csdnShieldBottomRecommendArticle() {
  564. log.info("屏蔽底部推荐文章");
  565. GM_addStyle(`main > div.recommend-box {display: none !important;}`);
  566. },
  567. /**
  568. * 屏蔽底部xx技能树
  569. */
  570. csdnShieldBottomSkillTree() {
  571. GM_addStyle(`#treeSkill{display: none !important;}`);
  572. },
  573. /**
  574. * 屏蔽底部悬浮工具栏
  575. */
  576. csdnShieldBottomFloatingToolbar() {
  577. log.info("屏蔽底部悬浮工具栏");
  578. GM_addStyle(`#toolBarBox{display: none !important;}`);
  579. },
  580. /**
  581. * 屏蔽左侧博客信息
  582. */
  583. shieldLeftBlogContainerAside() {
  584. log.success("【屏蔽】左侧博客信息");
  585. GM_addStyle(`aside.blog_container_aside{display: none !important;}`);
  586. },
  587. /**
  588. * 【屏蔽】右侧目录信息
  589. */
  590. shieldRightDirectoryInformation() {
  591. log.success("【屏蔽】右侧目录信息");
  592. GM_addStyle(`
  593. #rightAsideConcision,
  594. #rightAside{
  595. display: none !important;
  596. }
  597. `);
  598. },
  599. /**
  600. * 屏蔽顶部Toolbar
  601. */
  602. shieldTopToolbar() {
  603. GM_addStyle(`#toolbarBox{display: none !important;}`);
  604. },
  605. /**
  606. * 屏蔽文章内的选中搜索悬浮提示
  607. */
  608. shieldArticleSearchTip() {
  609. GM_addStyle(`#articleSearchTip{display: none !important;}`);
  610. },
  611. /**
  612. * 去除CSDN拦截其它网址的url并自动跳转
  613. */
  614. jumpRedirect() {
  615. /* https://link.csdn.net/?target=https%3A%2F%2Fjaist.dl.sourceforge.net%2Fproject%2Fportecle%2Fv1.11%2Fportecle-1.11.zip */
  616. if (
  617. window.location.hostname === "link.csdn.net" &&
  618. window.location.search.startsWith("?target")
  619. ) {
  620. /* 禁止CSDN拦截跳转 */
  621. window.stop();
  622. let search = window.location.search.replace(/^\?target=/gi, "");
  623. search = decodeURIComponent(search);
  624. let newURL = search;
  625. log.success(`跳转链接 ${newURL}`);
  626. window.location.href = newURL;
  627. }
  628. },
  629. /**
  630. * C知道
  631. */
  632. cKnow() {
  633. if (!window.location.href.startsWith("https://so.csdn.net/so/ai")) {
  634. return;
  635. }
  636. GM_addStyle(`
  637. div.username_mask_cover{
  638. background-image: none !important;
  639. }
  640. `);
  641. },
  642. /**
  643. * 初始化右侧工具栏的偏移(top、right)
  644. */
  645. initRightToolbarOffset() {
  646. GM_addStyle(`
  647. .csdn-side-toolbar{
  648. left: unset !important;
  649. }
  650. `);
  651. utils.waitNode(".csdn-side-toolbar").then((element) => {
  652. DOMUtils.css(element, {
  653. top:
  654. parseInt(PopsPanel.getValue("csdn_pc_rightToolbarTopOffset")) +
  655. "px",
  656. right:
  657. parseInt(
  658. PopsPanel.getValue("csdn_pc_rightToolbarRightOffset")
  659. ) + "px",
  660. });
  661. });
  662. },
  663. },
  664. Mobile: {
  665. /**
  666. * 初始化
  667. */
  668. init() {
  669. this.addCSS();
  670. PopsPanel.execMenu("csdn_mobile_shieldTopToolbar", () => {
  671. this.shieldTopToolbar();
  672. });
  673. PopsPanel.execMenu("CSDNAutoJumpRedirect_Mobile", () => {
  674. CSDN.blog.PC.jumpRedirect();
  675. });
  676. PopsPanel.execMenu("csdnMobile_notLimitCodePreMaxHeight", () => {
  677. this.notLimitCodePreMaxHeight();
  678. });
  679. PopsPanel.execMenu("csdnMobile_notLimitCommentMaxHeight", () => {
  680. this.notLimitCommentMaxHeight();
  681. });
  682. PopsPanel.execMenu("csdn_mobile_cknow", () => {
  683. this.cKnow();
  684. });
  685. PopsPanel.execMenu("csdnMobile_allowSelectText", () => {
  686. this.allowSelectText();
  687. });
  688. PopsPanel.execMenu("csdnMobile_autoExpandContent", () => {
  689. this.autoExpandContent();
  690. });
  691. PopsPanel.execMenu("csdn_mobile_blockBottomArticle", () => {
  692. this.blockBottomArticle();
  693. });
  694. PopsPanel.execMenu("csdn_mobile_blockComment", () => {
  695. this.blockComment();
  696. });
  697. DOMUtils.ready(() => {
  698. PopsPanel.execMenu("csdn_mobile_removeAds", () => {
  699. this.removeAds();
  700. });
  701. PopsPanel.execMenu("csdn_mobile_refactoringRecommendation", () => {
  702. this.refactoringRecommendation();
  703. });
  704. PopsPanel.execMenu("csdn_mobile_unBlockCopy", () => {
  705. CSDN.blog.PC.unBlockCopy();
  706. });
  707. });
  708. },
  709. getDefaultShieldCSS() {
  710. return `
  711. #operate,.feed-Sign-span,
  712. .view_comment_box,
  713. .weixin-shadowbox.wap-shadowbox,
  714. .feed-Sign-span,
  715. .user-desc.user-desc-fix,
  716. .comment_read_more_box,
  717. #content_views pre.set-code-hide .hide-preCode-box,
  718. /* 登录弹窗 */
  719. .passport-login-container,
  720. .hljs-button[data-title='登录后复制'],
  721. .article-show-more,
  722. #treeSkill,
  723. div.btn_open_app_prompt_div,
  724. div.readall_box,
  725. div.aside-header-fixed,
  726. div.feed-Sign-weixin,
  727. div.ios-shadowbox{
  728. display:none !important;
  729. }`;
  730. },
  731. addCSS() {
  732. let shieldCSS = PopsPanel.getValue(
  733. `csdn-mobile-shield-css`,
  734. this.getDefaultShieldCSS()
  735. );
  736. GM_addStyle(shieldCSS);
  737. GM_addStyle(`
  738. #mainBox{
  739. width: auto;
  740. }
  741. .user-desc.user-desc-fix{
  742. height: auto !important;
  743. overflow: auto !important;
  744. }
  745. .component-box .praise {
  746. background: #ff5722;
  747. border-radius: 5px;
  748. padding: 0px 8px;
  749. height: auto;
  750. }
  751. .component-box .praise,.component-box .share {
  752. color: #fff;
  753. }
  754. .component-box a {
  755. display: inline-block;
  756. font-size:xx-small;
  757. }
  758. .component-box {
  759. display: inline;
  760. margin: 0;
  761. position: relative;
  762. white-space:nowrap;
  763. }
  764. .csdn-edu-title{
  765. background: #4d6de1;
  766. border-radius: 5px;
  767. padding: 0px 8px;
  768. height: auto;
  769. color: #fff !important;
  770. }`);
  771. GM_addStyle(`
  772. .GM-csdn-dl{
  773. padding: .24rem .32rem;
  774. width: 100%;
  775. justify-content: space-between;
  776. -webkit-box-pack: justify;
  777. border-bottom: 1px solid #F5F6F7!important;
  778. }
  779. .GM-csdn-title{
  780. font-size: .3rem;
  781. color: #222226;
  782. letter-spacing: 0;
  783. line-height: .44rem;
  784. font-weight: 600;
  785. //max-height: .88rem;
  786. word-break: break-all;
  787. overflow: hidden;
  788. display: -webkit-box;
  789. -webkit-box-orient: vertical;
  790. -webkit-line-clamp: 2
  791. }
  792. .GM-csdn-title a{
  793. word-break: break-all;
  794. color: #222226;
  795. font-weight: 600;
  796. }
  797. .GM-csdn-title em,.GM-csdn-content em{
  798. font-style: normal;
  799. color: #fc5531
  800. }
  801. .GM-csdn-content{
  802. //max-width: 5.58rem;
  803. overflow: hidden;
  804. text-overflow: ellipsis;
  805. display: -webkit-box;
  806. -webkit-line-clamp: 1;
  807. -webkit-box-orient: vertical;
  808. color: #555666;
  809. font-size: .24rem;
  810. line-height: .34rem;
  811. max-height: .34rem;
  812. word-break: break-all;
  813. -webkit-box-flex: 1;
  814. -ms-flex: 1;
  815. flex: 1;
  816. margin-top: .16rem;
  817. }
  818. .GM-csdn-img img{
  819. width: 2.18rem;
  820. height: 1.58rem;
  821. //margin-left: .16rem
  822. }`);
  823. },
  824. /**
  825. * 屏蔽顶部Toolbar
  826. */
  827. shieldTopToolbar() {
  828. log.success("屏蔽顶部Toolbar");
  829. GM_addStyle(`
  830. #csdn-toolbar{
  831. display: none !important;
  832. }
  833. /* 内容顶部要归位 */
  834. body #main,
  835. .margin_sides{
  836. margin-top: unset !important;
  837. padding-top: unset !important;
  838. }
  839. #article .article_title{
  840. margin-top: .32rem !important;
  841. padding-top: unset !important;
  842. }
  843. `);
  844. },
  845. /**
  846. * 重构底部推荐
  847. */
  848. refactoringRecommendation() {
  849. function refactoring() {
  850. /* 反复执行的重构函数 */
  851. log.success("重构底部推荐");
  852. document.querySelectorAll(".container-fluid").forEach((item) => {
  853. /* 链接 */
  854. let url = "";
  855. /* 标题 */
  856. let title = "";
  857. /* 内容 */
  858. let content = "";
  859. /* 图片 */
  860. let img = "";
  861. /* 判断是否是CSDN资源下载 */
  862. let isCSDNDownload = false;
  863. /* 判断是否是CSDN-学院资源下载 */
  864. let isCSDNEduDownload = false;
  865. if (item.hasAttribute("data-url")) {
  866. /* 存在真正的URL */
  867. url = item.getAttribute("data-url");
  868. title = item.querySelector(
  869. ".recommend_title div.left"
  870. ).innerHTML;
  871. content = item.querySelector(".text").innerHTML;
  872. if (item.querySelectorAll(".recommend-img").length) {
  873. /* 如果有图片就加进去 */
  874. item.querySelectorAll(".recommend-img").forEach((item2) => {
  875. img += item2.innerHTML;
  876. });
  877. }
  878. } else {
  879. log.info("节点上无data-url");
  880. url = item.querySelector("a[data-type]").getAttribute("href");
  881. title = item.querySelector(
  882. ".recommend_title div.left"
  883. ).innerHTML;
  884. content = item.querySelector(".text").innerHTML;
  885. }
  886. var _URL_ = new URL(url);
  887. if (
  888. _URL_.host === "download.csdn.net" ||
  889. (_URL_.host === "www.iteye.com" &&
  890. _URL_.pathname.match(/^\/resource/gi))
  891. ) {
  892. /* 该链接为csdn资源下载 */
  893. log.info("该链接为csdn资源下载");
  894. isCSDNDownload = true;
  895. title =
  896. `<div class="component-box"><a class="praise" href="javascript:;">CSDN下载</a></div>` +
  897. title;
  898. } else if (_URL_.origin.match(/edu.csdn.net/gi)) {
  899. /* 该链接为csdn学院下载 */
  900. isCSDNEduDownload = true;
  901. log.info("该链接为csdn学院下载");
  902. title =
  903. `<div class="component-box"><a class="csdn-edu-title" href="javascript:;">CSDN学院</a></div>` +
  904. title;
  905. }
  906. item.setAttribute("class", "GM-csdn-dl");
  907. item.setAttribute("data-url", url);
  908. item.innerHTML = `<div class="GM-csdn-title"><div class="left">${title}</div></div><div class="GM-csdn-content">${content}</div><div class="GM-csdn-img">${img}</div>`;
  909. item.addEventListener("click", function () {
  910. if (PopsPanel.getValue("openNewTab")) {
  911. window.open(url, "_blank");
  912. } else {
  913. window.location.href = url;
  914. }
  915. });
  916. if (
  917. (isCSDNDownload || isCSDNEduDownload) &&
  918. PopsPanel.getValue("removeCSDNDownloadMobile")
  919. ) {
  920. item.remove();
  921. }
  922. });
  923. }
  924. let lockFunction = new utils.LockFunction(refactoring, this, 50);
  925. utils.waitNode("#recommend").then((element) => {
  926. log.success("重构底部推荐");
  927. lockFunction.run();
  928. utils.mutationObserver(element, {
  929. callback: lockFunction.run,
  930. config: { childList: true, subtree: true, attributes: true },
  931. });
  932. });
  933. },
  934. /**
  935. * 屏蔽底部文章
  936. */
  937. blockBottomArticle() {
  938. log.success("屏蔽底部文章");
  939. GM_addStyle("#recommend{display:none !important;}");
  940. },
  941. /**
  942. * 屏蔽评论
  943. */
  944. blockComment() {
  945. log.success("屏蔽评论");
  946. GM_addStyle("#comment{display:none !important;}");
  947. },
  948. /**
  949. * 去除广告
  950. */
  951. removeAds() {
  952. log.info("去除广告");
  953. /* 登录窗口 */
  954. waitForElementToRemove(".passport-login-container");
  955. /* 打开APP */
  956. waitForElementToRemove(
  957. ".btn_open_app_prompt_box.detail-open-removed"
  958. );
  959. /* 广告 */
  960. waitForElementToRemove(".add-firstAd");
  961. /* 打开CSDN APP 小程序看全文 */
  962. waitForElementToRemove("div.feed-Sign-weixin");
  963. /* ios版本提示 */
  964. waitForElementToRemove("div.ios-shadowbox");
  965. },
  966. /**
  967. * C知道
  968. */
  969. cKnow() {
  970. if (!window.location.href.startsWith("https://so.csdn.net/so/ai")) {
  971. return;
  972. }
  973. log.success("C知道屏蔽水印");
  974. GM_addStyle(`
  975. div.username_mask_cover{
  976. background-image: none !important;
  977. }
  978. `);
  979. },
  980. /**
  981. * 不限制代码块最大高度
  982. */
  983. notLimitCodePreMaxHeight() {
  984. log.success("不限制代码块最大高度");
  985. GM_addStyle(`
  986. pre{
  987. max-height: unset !important;
  988. }
  989. `);
  990. },
  991. /**
  992. * 不限制评论区最大高度
  993. */
  994. notLimitCommentMaxHeight() {
  995. log.success("不限制评论区最大高度");
  996. GM_addStyle(`
  997. #comment{
  998. max-height: none !important;
  999. }
  1000. `);
  1001. },
  1002. /**
  1003. * 允许选择文字
  1004. */
  1005. allowSelectText() {
  1006. log.success("允许选择文字");
  1007. GM_addStyle(`
  1008. #content_views,
  1009. #content_views pre,
  1010. #content_views pre code{
  1011. webkit-touch-callout: text !important;
  1012. -webkit-user-select: text !important;
  1013. -khtml-user-select: text !important;
  1014. -moz-user-select: text !important;
  1015. -ms-user-select: text !important;
  1016. user-select: text !important;
  1017. }
  1018. `);
  1019. },
  1020. /**
  1021. * 自动展开内容
  1022. */
  1023. autoExpandContent() {
  1024. log.success("自动展开内容");
  1025. GM_addStyle(`
  1026. #content_views pre.set-code-hide,
  1027. .article_content{
  1028. height: 100% !important;
  1029. overflow: auto !important;
  1030. }
  1031. `);
  1032. },
  1033. },
  1034. /**
  1035. * 函数入口
  1036. */
  1037. init() {
  1038. if (utils.isPhone()) {
  1039. log.success("移动端模式");
  1040. this.Mobile.init();
  1041. } else {
  1042. log.success("桌面端模式");
  1043. this.PC.init();
  1044. }
  1045. },
  1046. },
  1047. blogHuaWei: {
  1048. /**
  1049. * 判断是否是CSDN
  1050. */
  1051. isBlogRouter() {
  1052. return Boolean(/huaweicloud.csdn.net/i.test(window.location.origin));
  1053. },
  1054. PC: {
  1055. /**
  1056. * 初始化
  1057. */
  1058. init() {
  1059. this.addCSS();
  1060. if (
  1061. PopsPanel.getValue(
  1062. "huaweiCSDNShieldCloudDeveloperTaskChallengeEvent"
  1063. )
  1064. ) {
  1065. this.huaweiCSDNShieldCloudDeveloperTaskChallengeEvent();
  1066. }
  1067. if (PopsPanel.getValue("huaweiCSDNShieldLeftFloatingButton")) {
  1068. this.huaweiCSDNShieldLeftFloatingButton();
  1069. }
  1070. if (PopsPanel.getValue("huaweiCSDNBlockRightColumn")) {
  1071. this.huaweiCSDNBlockRightColumn();
  1072. }
  1073. if (
  1074. PopsPanel.getValue("huaweiCSDNBlockRecommendedContentAtTheBottom")
  1075. ) {
  1076. this.huaweiCSDNBlockRecommendedContentAtTheBottom();
  1077. }
  1078. if (
  1079. PopsPanel.getValue(
  1080. "huaweiCSDNShieldTheBottomForMoreRecommendations"
  1081. )
  1082. ) {
  1083. this.huaweiCSDNShieldTheBottomForMoreRecommendations();
  1084. }
  1085. },
  1086. getDefaultShieldCSS() {
  1087. return `
  1088. /* 底部免费抽xxx奖品广告 */
  1089. div.siderbar-box,
  1090. /* 华为开发者联盟加入社区 */
  1091. div.user-desc.user-desc-fix,
  1092. /* 点击阅读全文 */
  1093. div.article-show-more{
  1094. display: none !important;
  1095. }`;
  1096. },
  1097. addCSS() {
  1098. let shieldCSS = PopsPanel.getValue(
  1099. `csdn-blog-huawei-shield-css`,
  1100. this.getDefaultShieldCSS()
  1101. );
  1102. GM_addStyle(shieldCSS);
  1103. GM_addStyle(`
  1104. /* 自动展开全文 */
  1105. .main-content .user-article{
  1106. height: auto !important;
  1107. overflow: auto !important;
  1108. }
  1109. `);
  1110. },
  1111. /**
  1112. * 屏蔽云开发者任务挑战活动
  1113. */
  1114. huaweiCSDNShieldCloudDeveloperTaskChallengeEvent() {
  1115. let GM_cookie = new utils.GM_Cookie();
  1116. GM_cookie.set({ name: "show_join_group_index", value: 1 });
  1117. log.success("屏蔽云开发者任务挑战活动");
  1118. },
  1119. /**
  1120. * 屏蔽左侧悬浮按钮
  1121. */
  1122. huaweiCSDNShieldLeftFloatingButton() {
  1123. log.success(
  1124. "屏蔽左侧悬浮按钮,包括当前阅读量、点赞按钮、评论按钮、分享按钮"
  1125. );
  1126. GM_addStyle(`
  1127. div.toolbar-wrapper.article-interact-bar{
  1128. display: none !important;
  1129. }`);
  1130. },
  1131. /**
  1132. * 屏蔽右侧栏
  1133. */
  1134. huaweiCSDNBlockRightColumn() {
  1135. log.success("屏蔽右侧栏,包括相关产品-活动日历-运营活动-热门标签");
  1136. GM_addStyle(`
  1137. div.page-home-right.dp-aside-right{
  1138. display: none !important;
  1139. }
  1140. `);
  1141. },
  1142. /**
  1143. * 屏蔽底部推荐内容
  1144. */
  1145. huaweiCSDNBlockRecommendedContentAtTheBottom() {
  1146. log.success("屏蔽底部推荐内容");
  1147. GM_addStyle(`
  1148. div.recommend-card-box{
  1149. display: none !important;
  1150. }`);
  1151. },
  1152. /**
  1153. * 屏蔽底部更多推荐
  1154. */
  1155. huaweiCSDNShieldTheBottomForMoreRecommendations() {
  1156. log.success("屏蔽底部更多推荐");
  1157. GM_addStyle(`
  1158. div.more-article{
  1159. display: none !important;
  1160. }`);
  1161. },
  1162. },
  1163. },
  1164. wenku: {
  1165. isWenKuRouter() {
  1166. return Boolean(/wenku.csdn.net/i.test(window.location.origin));
  1167. },
  1168. PC: {
  1169. init() {
  1170. this.addCSS();
  1171. if (PopsPanel.getValue("wenku_shieldResourceRecommend")) {
  1172. this.shieldResourceRecommend();
  1173. }
  1174. if (PopsPanel.getValue("wenku_shieldRightUserInfo")) {
  1175. this.shieldRightUserInfo();
  1176. }
  1177. if (PopsPanel.getValue("wenku_shieldRightToolBar")) {
  1178. this.shieldRightToolBar();
  1179. }
  1180. },
  1181. getDefaultShieldCSS() {
  1182. return ``;
  1183. },
  1184. addCSS() {
  1185. let shieldCSS = PopsPanel.getValue(
  1186. "csdn-wenku-shield-css",
  1187. this.getDefaultShieldCSS()
  1188. );
  1189. GM_addStyle(shieldCSS);
  1190. },
  1191. /**
  1192. * 【屏蔽】资源推荐
  1193. */
  1194. shieldResourceRecommend() {
  1195. GM_addStyle(`#recommend{display:none !important;}`);
  1196. },
  1197. /**
  1198. * 【屏蔽】右侧用户信息
  1199. */
  1200. shieldRightUserInfo() {
  1201. GM_addStyle(`.layout-right{display:none !important;}`);
  1202. },
  1203. /**
  1204. * 【屏蔽】右侧悬浮工具栏
  1205. */
  1206. shieldRightToolBar() {
  1207. GM_addStyle(`.csdn-side-toolbar {display:none !important;}`);
  1208. },
  1209. },
  1210. },
  1211. };
  1212.  
  1213. /**
  1214. * 配置面板
  1215. */
  1216. const PopsPanel = {
  1217. /** 数据 */
  1218. $data: {
  1219. /**
  1220. * 菜单项的默认值
  1221. * @type {UtilsDictionaryConstructor<string,any>}
  1222. */
  1223. data: new utils.Dictionary(),
  1224. /** 脚本名,一般用在设置的标题上 */
  1225. scriptName: GM_info?.script?.name || "",
  1226. /** 菜单项的总值在本地数据配置的键名 */
  1227. key: "GM_Panel",
  1228. /** 菜单项在attributes上配置的菜单键 */
  1229. attributeKeyName: "data-key",
  1230. /** 菜单项在attributes上配置的菜单默认值 */
  1231. attributeDefaultValueName: "data-default-value",
  1232. },
  1233. /** 监听器 */
  1234. $listener: {
  1235. /**
  1236. * 值改变的监听器
  1237. * @type {UtilsDictionaryConstructor<string,{
  1238. * id: number,
  1239. * key: string,
  1240. * callback: Function
  1241. * }>}
  1242. */
  1243. listenData: new utils.Dictionary(),
  1244. },
  1245. /** 初始化 */
  1246. init() {
  1247. this.initPanelDefaultValue();
  1248. this.initExtensionsMenu();
  1249. },
  1250. /**
  1251. * 初始化菜单
  1252. */
  1253. initExtensionsMenu() {
  1254. if (unsafeWindow.top !== unsafeWindow.self) {
  1255. return;
  1256. }
  1257. GM_Menu.add([
  1258. {
  1259. key: "show_pops_panel_setting",
  1260. text: "⚙ 设置",
  1261. autoReload: false,
  1262. isStoreValue: false,
  1263. showText(text) {
  1264. return text;
  1265. },
  1266. callback: () => {
  1267. this.showPanel();
  1268. },
  1269. },
  1270. {
  1271. key: "gotoCSDNCKnow",
  1272. text: "⚙ 前往C知道",
  1273. autoReload: false,
  1274. showText(text) {
  1275. return text;
  1276. },
  1277. callback() {
  1278. window.open("https://so.csdn.net/so/ai?", "_blank");
  1279. },
  1280. },
  1281. ]);
  1282. },
  1283. /**
  1284. * 初始化本地设置默认的值
  1285. */
  1286. initPanelDefaultValue() {
  1287. let that = this;
  1288. /**
  1289. * 设置默认值
  1290. * @param {PopsPanelFormsTotalDetails|PopsPanelFormsDetails} config
  1291. */
  1292. function initDefaultValue(config) {
  1293. if (!config["attributes"]) {
  1294. /* 必须配置attributes属性,用于存储菜单的键和默认值 */
  1295. return;
  1296. }
  1297. /* 获取键名 */
  1298. let key = config["attributes"][that.$data.attributeKeyName];
  1299. /* 获取默认值 */
  1300. let defaultValue =
  1301. config["attributes"][that.$data.attributeDefaultValueName];
  1302. if (key == null) {
  1303. console.warn("请先配置键", config);
  1304. return;
  1305. }
  1306. /* 存储到内存中 */
  1307. if (that.$data.data.has(key)) {
  1308. console.warn("请检查该key(已存在): " + key);
  1309. }
  1310. that.$data.data.set(key, defaultValue);
  1311. }
  1312. let contentConfigList = this.getPanelContentConfig();
  1313. for (let index = 0; index < contentConfigList.length; index++) {
  1314. let leftContentConfigItem = contentConfigList[index];
  1315. if (!leftContentConfigItem["forms"]) {
  1316. /* 不存在forms */
  1317. continue;
  1318. }
  1319. let rightContentConfigList = leftContentConfigItem["forms"];
  1320. for (
  1321. let formItemIndex = 0;
  1322. formItemIndex < rightContentConfigList.length;
  1323. formItemIndex++
  1324. ) {
  1325. let rightContentConfigItem = rightContentConfigList[formItemIndex];
  1326. let childFormConfigList = rightContentConfigItem["forms"];
  1327. if (childFormConfigList) {
  1328. /* 该项是右侧区域-容器项的子项的配置 */
  1329. for (
  1330. let formChildConfigIndex = 0;
  1331. formChildConfigIndex < childFormConfigList.length;
  1332. formChildConfigIndex++
  1333. ) {
  1334. initDefaultValue(childFormConfigList[formChildConfigIndex]);
  1335. }
  1336. } else {
  1337. /* 该项是右侧区域-容器项的配置 */
  1338. initDefaultValue(rightContentConfigItem);
  1339. }
  1340. }
  1341. }
  1342. },
  1343. /**
  1344. * 自动判断菜单是否启用,然后执行回调
  1345. * @param {string} key
  1346. * @param {Function} callback 回调
  1347. */
  1348. execMenu(key, callback) {
  1349. if (typeof key !== "string") {
  1350. throw new TypeError("key 必须是字符串");
  1351. }
  1352. if (PopsPanel.getValue(key)) {
  1353. callback();
  1354. }
  1355. },
  1356. /**
  1357. * 设置值
  1358. * @param {string} key 键
  1359. * @param {any} value 值
  1360. */
  1361. setValue(key, value) {
  1362. let locaData = GM_getValue(this.$data.key, {});
  1363. let oldValue = locaData[key];
  1364. locaData[key] = value;
  1365. GM_setValue(this.$data.key, locaData);
  1366. if (this.$listener.listenData.has(key)) {
  1367. this.$listener.listenData.get(key).callback(key, oldValue, value);
  1368. }
  1369. },
  1370. /**
  1371. * 获取值
  1372. * @param {string} key 键
  1373. * @param {boolean} defaultValue 默认值
  1374. * @returns {any}
  1375. */
  1376. getValue(key, defaultValue) {
  1377. let locaData = GM_getValue(this.$data.key, {});
  1378. let localValue = locaData[key];
  1379. if (localValue == null) {
  1380. /* 值不存在或值为null/undefined或只有键但无值 */
  1381. if (this.$data.data.has(key)) {
  1382. /* 先判断是否是菜单配置的键 */
  1383. /* 是的话取出值并返回 */
  1384. return this.$data.data.get(key);
  1385. }
  1386. return defaultValue;
  1387. }
  1388. return localValue;
  1389. },
  1390. /**
  1391. * 删除值
  1392. * @param {string} key 键
  1393. */
  1394. deleteValue(key) {
  1395. let locaData = GM_getValue(this.$data.key, {});
  1396. let oldValue = locaData[key];
  1397. Reflect.deleteProperty(locaData, key);
  1398. GM_setValue(this.$data.key, locaData);
  1399. if (this.$listener.listenData.has(key)) {
  1400. this.$listener.listenData.get(key).callback(key, oldValue, void 0);
  1401. }
  1402. },
  1403. /**
  1404. * 监听调用setValue、deleteValue
  1405. * @param {string} key 需要监听的键
  1406. * @param {(key: string,oldValue: any,newValue: any)=>void} callback
  1407. */
  1408. addValueChangeListener(key, callback) {
  1409. let listenerId = Math.random();
  1410. this.$listener.listenData.set(key, {
  1411. id: listenerId,
  1412. key,
  1413. callback,
  1414. });
  1415. return listenerId;
  1416. },
  1417. /**
  1418. * 移除监听
  1419. * @param {number} listenerId 监听的id
  1420. */
  1421. removeValueChangeListener(listenerId) {
  1422. let deleteKey = null;
  1423. for (const [key, value] of this.$listener.listenData.entries()) {
  1424. if (value.id === listenerId) {
  1425. break;
  1426. }
  1427. }
  1428. this.$listener.listenData.delete(deleteKey);
  1429. },
  1430. /**
  1431. * 显示设置面板
  1432. */
  1433. showPanel() {
  1434. pops.panel({
  1435. title: {
  1436. text: `${GM_info?.script?.name || "CSDN优化"}-设置`,
  1437. position: "center",
  1438. },
  1439. content: this.getPanelContentConfig(),
  1440. mask: {
  1441. enable: true,
  1442. clickEvent: {
  1443. toClose: true,
  1444. },
  1445. },
  1446. width: pops.isPhone() ? "92vw" : "800px",
  1447. height: pops.isPhone() ? "80vh" : "600px",
  1448. only: true,
  1449. drag: true,
  1450. });
  1451. },
  1452. /**
  1453. * 获取按钮配置
  1454. * @param {string} text 文字
  1455. * @param {string} key 键
  1456. * @param {boolean} defaultValue 默认值
  1457. * @param {?(event:Event,value: boolean)=>boolean} _callback_ 点击回调
  1458. * @param {string|undefined} description 描述
  1459. */
  1460. getSwtichDetail(text, key, defaultValue, _callback_, description) {
  1461. /**
  1462. * @type {PopsPanelSwitchDetails}
  1463. */
  1464. let result = {
  1465. text: text,
  1466. type: "switch",
  1467. description: description,
  1468. attributes: {},
  1469. getValue() {
  1470. return Boolean(PopsPanel.getValue(key, defaultValue));
  1471. },
  1472. callback(event, value) {
  1473. log.success(`${value ? "开启" : "关闭"} ${text}`);
  1474. if (typeof _callback_ === "function") {
  1475. if (_callback_(event, value)) {
  1476. return;
  1477. }
  1478. }
  1479. PopsPanel.setValue(key, Boolean(value));
  1480. },
  1481. };
  1482. result.attributes[this.$data.attributeKeyName] = key;
  1483. result.attributes[this.$data.attributeDefaultValueName] =
  1484. Boolean(defaultValue);
  1485. return result;
  1486. },
  1487. /**
  1488. * 获取自定义配置的规则的textarea
  1489. * @returns {PopsPanelOwnDetails}
  1490. */
  1491. getOwnextAreaRule(text, key, defaultValue, className) {
  1492. return {
  1493. text: text,
  1494. type: "forms",
  1495. forms: [
  1496. {
  1497. type: "own",
  1498. afterAddToUListCallBack(formConfig, rightContainerOptions) {
  1499. DOMUtils.on(
  1500. rightContainerOptions.formHeaderDivElement.querySelector("a"),
  1501. "click",
  1502. void 0,
  1503. () => {
  1504. PopsPanel.deleteValue(key);
  1505. rightContainerOptions.ulElement.querySelector(
  1506. "textarea"
  1507. ).value = defaultValue;
  1508. Qmsg.success("已重置");
  1509. }
  1510. );
  1511. },
  1512. getLiElementCallBack(liElement) {
  1513. let $textAreaContainer = DOMUtils.createElement("div", {
  1514. className: `pops-panel-textarea ${className}`,
  1515. innerHTML: `
  1516. <style type="text/css">
  1517. .${className}{
  1518. width: 100%;
  1519. }
  1520. .${className} textarea{
  1521. min-height: 400px;
  1522. white-space: pre;
  1523. border-radius: 0 !important;
  1524. }
  1525. </style>
  1526. <textarea></textarea>
  1527. `,
  1528. });
  1529. let $textArea = $textAreaContainer.querySelector("textarea");
  1530. $textArea.value = PopsPanel.getValue(key, defaultValue);
  1531. liElement.appendChild($textAreaContainer);
  1532. DOMUtils.on(
  1533. $textArea,
  1534. "input propertychange",
  1535. void 0,
  1536. utils.debounce(() => {
  1537. PopsPanel.setValue(key, $textArea.value);
  1538. }, 100)
  1539. );
  1540. return liElement;
  1541. },
  1542. },
  1543. ],
  1544. };
  1545. },
  1546. /**
  1547. * 获取配置内容
  1548. * @returns {PopsPanelContentConfig[]}
  1549. */
  1550. getPanelContentConfig() {
  1551. return [
  1552. {
  1553. id: "csdn-panel-config-pc",
  1554. title: "博客",
  1555. isDefault() {
  1556. return CSDN.blog.isBlogRouter() && !utils.isPhone();
  1557. },
  1558. forms: [
  1559. {
  1560. text: "屏蔽",
  1561. type: "forms",
  1562. forms: [
  1563. PopsPanel.getSwtichDetail(
  1564. "【屏蔽】登录弹窗",
  1565. "shieldLoginDialog",
  1566. true
  1567. ),
  1568. PopsPanel.getSwtichDetail(
  1569. "【屏蔽】底部xx技能树",
  1570. "csdnShieldBottomSkillTree",
  1571. false
  1572. ),
  1573. PopsPanel.getSwtichDetail(
  1574. "【屏蔽】左侧博客信息",
  1575. "csdn_pc_shieldLeftBlogContainerAside",
  1576. false
  1577. ),
  1578. PopsPanel.getSwtichDetail(
  1579. "【屏蔽】右侧目录信息",
  1580. "csdn_pc_shieldRightDirectoryInformation",
  1581. false
  1582. ),
  1583. PopsPanel.getSwtichDetail(
  1584. "【屏蔽】右侧工具栏",
  1585. "csdnShieldfloatingButton",
  1586. false
  1587. ),
  1588. PopsPanel.getSwtichDetail(
  1589. "【屏蔽】顶部工具栏",
  1590. "csdn_pc_shieldTopToolbar",
  1591. false
  1592. ),
  1593. PopsPanel.getSwtichDetail(
  1594. "【屏蔽】搜索悬浮工具栏",
  1595. "csdn_pc_shieldArticleSearchTip",
  1596. false,
  1597. void 0,
  1598. "选中文字弹出的,例如:搜索、评论、笔记"
  1599. ),
  1600. PopsPanel.getSwtichDetail(
  1601. "【屏蔽】底部的悬浮工具栏",
  1602. "csdnShieldBottomFloatingToolbar",
  1603. false
  1604. ),
  1605. PopsPanel.getSwtichDetail(
  1606. "【屏蔽】C知道的背景水印",
  1607. "csdn_pc_cknow",
  1608. false
  1609. ),
  1610. ],
  1611. },
  1612. {
  1613. text: "功能",
  1614. type: "forms",
  1615. forms: [
  1616. {
  1617. text: "右侧工具栏的right偏移",
  1618. type: "slider",
  1619. attributes: {
  1620. "data-key": "csdn_pc_rightToolbarRightOffset",
  1621. "data-default-value": 90,
  1622. },
  1623. getValue() {
  1624. return PopsPanel.getValue(
  1625. this.attributes["data-key"],
  1626. this.attributes["data-default-value"]
  1627. );
  1628. },
  1629. getToolTipContent(value) {
  1630. return `当前:${value}px,默认:${this.attributes["data-default-value"]}px`;
  1631. },
  1632. callback(event, value) {
  1633. PopsPanel.setValue(this.attributes["data-key"], value);
  1634. let csdnSideToolbar =
  1635. document.querySelector(".csdn-side-toolbar");
  1636. DOMUtils.css(csdnSideToolbar, {
  1637. right: value + "px",
  1638. });
  1639. },
  1640. min: 0,
  1641. max: document.documentElement.clientWidth,
  1642. },
  1643. {
  1644. text: "右侧工具栏的top偏移",
  1645. type: "slider",
  1646. attributes: {
  1647. "data-key": "csdn_pc_rightToolbarTopOffset",
  1648. "data-default-value": 140,
  1649. },
  1650. getValue() {
  1651. return PopsPanel.getValue(
  1652. this.attributes["data-key"],
  1653. this.attributes["data-default-value"]
  1654. );
  1655. },
  1656. getToolTipContent(value) {
  1657. return `当前:${value}px,默认:${this.attributes["data-default-value"]}px`;
  1658. },
  1659. callback(event, value) {
  1660. PopsPanel.setValue(this.attributes["data-key"], value);
  1661. let csdnSideToolbar =
  1662. document.querySelector(".csdn-side-toolbar");
  1663. DOMUtils.css(csdnSideToolbar, {
  1664. top: value + "px",
  1665. });
  1666. },
  1667. min: 0,
  1668. max: document.documentElement.clientHeight,
  1669. },
  1670. PopsPanel.getSwtichDetail(
  1671. "重定向链接",
  1672. "CSDNAutoJumpRedirect_PC",
  1673. true,
  1674. undefined,
  1675. "自动跳转CSDN拦截的Url链接"
  1676. ),
  1677. ],
  1678. },
  1679. {
  1680. text: "内容",
  1681. type: "forms",
  1682. forms: [
  1683. PopsPanel.getSwtichDetail(
  1684. "自动展开内容块",
  1685. "autoExpandContent",
  1686. false
  1687. ),
  1688. PopsPanel.getSwtichDetail(
  1689. "全文居中",
  1690. "articleCenter",
  1691. true,
  1692. function (event, enable) {
  1693. if (enable) {
  1694. alert(
  1695. "为了更好的呈现效果,请开启功能:【屏蔽】左侧博客信息、【屏蔽】右侧目录信息"
  1696. );
  1697. }
  1698. }
  1699. ),
  1700. ],
  1701. },
  1702. {
  1703. text: "评论",
  1704. type: "forms",
  1705. forms: [
  1706. PopsPanel.getSwtichDetail(
  1707. "屏蔽",
  1708. "csdnPC_blockComment",
  1709. false,
  1710. void 0,
  1711. "屏蔽评论"
  1712. ),
  1713. PopsPanel.getSwtichDetail(
  1714. "优化评论的位置",
  1715. "csdn_pc_restoreComments",
  1716. true
  1717. ),
  1718. PopsPanel.getSwtichDetail(
  1719. "添加前往评论的按钮",
  1720. "csdn_pc_addGotoRecommandButton",
  1721. true
  1722. ),
  1723. ],
  1724. },
  1725. {
  1726. text: "底部文章",
  1727. type: "forms",
  1728. forms: [
  1729. PopsPanel.getSwtichDetail(
  1730. "屏蔽",
  1731. "csdnShieldBottomRecommendArticle",
  1732. false,
  1733. void 0,
  1734. "屏蔽底部文章"
  1735. ),
  1736. PopsPanel.getSwtichDetail(
  1737. "标识CSDN下载",
  1738. "csdn_pc_identityCSDNDownload",
  1739. true,
  1740. void 0,
  1741. "使用红框标识"
  1742. ),
  1743. PopsPanel.getSwtichDetail(
  1744. "移除资源下载的文章",
  1745. "removeCSDNDownloadPC",
  1746. false,
  1747. void 0,
  1748. "移除download.csdn.net、www.iteye.com、edu.csdn.net的文章链接"
  1749. ),
  1750. ],
  1751. },
  1752. {
  1753. text: "劫持/拦截",
  1754. type: "forms",
  1755. forms: [
  1756. PopsPanel.getSwtichDetail(
  1757. "拦截-复制的小尾巴",
  1758. "csdn_pc_removeClipboardHijacking",
  1759. true
  1760. ),
  1761. PopsPanel.getSwtichDetail(
  1762. "劫持-禁止复制",
  1763. "csdn_pc_unBlockCopy",
  1764. true,
  1765. undefined,
  1766. "允许点击复制按钮进行复制"
  1767. ),
  1768. ],
  1769. },
  1770. this.getOwnextAreaRule(
  1771. "自定义屏蔽CSS,<a href='javascript:;'>点击重置</a>",
  1772. "csdn-pc-shield-css",
  1773. CSDN.blog.PC.getDefaultShieldCSS(),
  1774. "csdn-pc-shield-css"
  1775. ),
  1776. ],
  1777. },
  1778. {
  1779. id: "csdn-panel-config-mobile",
  1780. title: "博客(移动端)",
  1781. isDefault() {
  1782. return CSDN.blog.isBlogRouter() && utils.isPhone();
  1783. },
  1784. forms: [
  1785. {
  1786. text: "功能",
  1787. type: "forms",
  1788. forms: [
  1789. PopsPanel.getSwtichDetail(
  1790. "重定向链接",
  1791. "CSDNAutoJumpRedirect_Mobile",
  1792. true,
  1793. void 0,
  1794. "自动跳转CSDN拦截的Url链接"
  1795. ),
  1796. ],
  1797. },
  1798. {
  1799. text: "屏蔽",
  1800. type: "forms",
  1801. forms: [
  1802. PopsPanel.getSwtichDetail(
  1803. "【屏蔽】广告",
  1804. "csdn_mobile_removeAds",
  1805. true,
  1806. void 0,
  1807. "包括:登录弹窗、打开APP、ios版本提示等"
  1808. ),
  1809. PopsPanel.getSwtichDetail(
  1810. "【屏蔽】C知道的背景水印",
  1811. "csdn_mobile_cknow",
  1812. true
  1813. ),
  1814. PopsPanel.getSwtichDetail(
  1815. "【屏蔽】顶部Toolbar",
  1816. "csdn_mobile_shieldTopToolbar",
  1817. false
  1818. ),
  1819. ],
  1820. },
  1821. {
  1822. text: "内容",
  1823. type: "forms",
  1824. forms: [
  1825. PopsPanel.getSwtichDetail(
  1826. "允许选中文字",
  1827. "csdnMobile_allowSelectText",
  1828. true,
  1829. void 0,
  1830. "设置user-select: text;"
  1831. ),
  1832. PopsPanel.getSwtichDetail(
  1833. "自动展开",
  1834. "csdnMobile_autoExpandContent",
  1835. true,
  1836. void 0,
  1837. "包括内容、代码块"
  1838. ),
  1839. PopsPanel.getSwtichDetail(
  1840. "不限制代码块的最大高度",
  1841. "csdnMobile_notLimitCodePreMaxHeight",
  1842. false,
  1843. void 0,
  1844. "让代码块的高度直接被撑开"
  1845. ),
  1846. ],
  1847. },
  1848. {
  1849. text: "评论",
  1850. type: "forms",
  1851. forms: [
  1852. PopsPanel.getSwtichDetail(
  1853. "屏蔽",
  1854. "csdn_mobile_blockComment",
  1855. false,
  1856. void 0,
  1857. "屏蔽评论区"
  1858. ),
  1859. PopsPanel.getSwtichDetail(
  1860. "不限制评论区的最大高度",
  1861. "csdnMobile_notLimitCommentMaxHeight",
  1862. true,
  1863. void 0,
  1864. "让评论区高度直接被撑开"
  1865. ),
  1866. ],
  1867. },
  1868. {
  1869. text: "底部文章",
  1870. type: "forms",
  1871. forms: [
  1872. PopsPanel.getSwtichDetail(
  1873. "屏蔽",
  1874. "csdn_mobile_blockBottomArticle",
  1875. false,
  1876. void 0,
  1877. "屏蔽底部文章"
  1878. ),
  1879. PopsPanel.getSwtichDetail(
  1880. "移除资源下载的文章",
  1881. "removeCSDNDownloadMobile",
  1882. false,
  1883. void 0,
  1884. "移除download.csdn.net、www.iteye.com、edu.csdn.net的文章链接"
  1885. ),
  1886. PopsPanel.getSwtichDetail(
  1887. "重构",
  1888. "csdn_mobile_refactoringRecommendation",
  1889. true,
  1890. void 0,
  1891. "样式统一化"
  1892. ),
  1893. PopsPanel.getSwtichDetail(
  1894. "新标签页打开",
  1895. "openNewTab",
  1896. true,
  1897. void 0,
  1898. "点击文章,新标签页打开"
  1899. ),
  1900. ],
  1901. },
  1902. {
  1903. text: "劫持/拦截",
  1904. type: "forms",
  1905. forms: [
  1906. PopsPanel.getSwtichDetail(
  1907. "劫持-禁止复制",
  1908. "csdn_mobile_unBlockCopy",
  1909. true,
  1910. undefined,
  1911. "允许点击复制按钮进行复制"
  1912. ),
  1913. ],
  1914. },
  1915. this.getOwnextAreaRule(
  1916. "自定义屏蔽CSS,<a href='javascript:;'>点击重置</a>",
  1917. "csdn-mobile-shield-css",
  1918. CSDN.blog.Mobile.getDefaultShieldCSS(),
  1919. "csdn-mobile-shield-css"
  1920. ),
  1921. ],
  1922. },
  1923. {
  1924. id: "csdn-panel-config-huawei",
  1925. title: "博客(华为开发者联盟)",
  1926. isDefault() {
  1927. return CSDN.blogHuaWei.isBlogRouter();
  1928. },
  1929. forms: [
  1930. {
  1931. text: "屏蔽",
  1932. type: "forms",
  1933. forms: [
  1934. PopsPanel.getSwtichDetail(
  1935. "【屏蔽】云开发者任务挑战活动",
  1936. "huaweiCSDNShieldCloudDeveloperTaskChallengeEvent",
  1937. true
  1938. ),
  1939. PopsPanel.getSwtichDetail(
  1940. "【屏蔽】左侧悬浮按钮",
  1941. "huaweiCSDNShieldLeftFloatingButton",
  1942. false,
  1943. function (event, enable) {
  1944. if (enable) {
  1945. alert(
  1946. "开启后将屏蔽【当前阅读量】、【点赞按钮】、【评论按钮】、【分享按钮】"
  1947. );
  1948. }
  1949. }
  1950. ),
  1951. PopsPanel.getSwtichDetail(
  1952. "【屏蔽】右侧栏",
  1953. "huaweiCSDNBlockRightColumn",
  1954. false,
  1955. function (event, enable) {
  1956. if (enable) {
  1957. alert(
  1958. "开启后将屏蔽【相关产品】-【活动日历】-【运营活动】-【热门标签】"
  1959. );
  1960. }
  1961. }
  1962. ),
  1963. PopsPanel.getSwtichDetail(
  1964. "【屏蔽】底部推荐内容",
  1965. "huaweiCSDNBlockRecommendedContentAtTheBottom",
  1966. false
  1967. ),
  1968. PopsPanel.getSwtichDetail(
  1969. "【屏蔽】底部更多推荐",
  1970. "huaweiCSDNShieldTheBottomForMoreRecommendations",
  1971. false
  1972. ),
  1973. ],
  1974. },
  1975. this.getOwnextAreaRule(
  1976. "自定义屏蔽CSS,<a href='javascript:;'>点击重置</a>",
  1977. "csdn-blog-huawei-shield-css",
  1978. CSDN.blogHuaWei.PC.getDefaultShieldCSS(),
  1979. "csdn-blog-huawei-shield-css"
  1980. ),
  1981. ],
  1982. },
  1983. {
  1984. id: "csdn-panel-config-pc",
  1985. title: "文库",
  1986. isDefault() {
  1987. return CSDN.wenku.PC.isWenkuRouter();
  1988. },
  1989. forms: [
  1990. {
  1991. text: "屏蔽",
  1992. type: "forms",
  1993. forms: [
  1994. PopsPanel.getSwtichDetail(
  1995. "【屏蔽】资源推荐",
  1996. "wenku_shieldResourceRecommend",
  1997. false
  1998. ),
  1999. PopsPanel.getSwtichDetail(
  2000. "【屏蔽】右侧用户信息",
  2001. "wenku_shieldRightUserInfo",
  2002. false
  2003. ),
  2004. PopsPanel.getSwtichDetail(
  2005. "【屏蔽】右侧悬浮工具栏",
  2006. "wenku_shieldRightToolBar",
  2007. false
  2008. ),
  2009. ],
  2010. },
  2011. this.getOwnextAreaRule(
  2012. "自定义屏蔽CSS,<a href='javascript:;'>点击重置</a>",
  2013. "csdn-wenku-shield-css",
  2014. CSDN.wenku.PC.getDefaultShieldCSS(),
  2015. "csdn-wenku-shield-css"
  2016. ),
  2017. ],
  2018. },
  2019. ];
  2020. },
  2021. };
  2022.  
  2023. PopsPanel.init();
  2024.  
  2025. if (CSDN.blogHuaWei.isBlogRouter()) {
  2026. CSDN.blogHuaWei.PC.init();
  2027. } else if (CSDN.blog.isBlogRouter()) {
  2028. CSDN.blog.init();
  2029. } else if (CSDN.wenku.isWenKuRouter()) {
  2030. CSDN.wenku.PC.init();
  2031. } else {
  2032. log.error("暂未适配,请反馈开发者:" + globalThis.location.href);
  2033. }
  2034. })();