CSDN优化

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

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

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