Codeforces_spoiler_tutorial

Wrap spoilers in Codeforces tutorial in spoiler blocks

  1. // ==UserScript==
  2. // @name Codeforces_spoiler_tutorial
  3. // @version 0.2.0
  4. // @description Wrap spoilers in Codeforces tutorial in spoiler blocks
  5. // @match *://codeforces.com/blog/entry/*
  6. // @match *://codeforces.com/blog/entry/*
  7. // @match *://codeforces.com/contest/*
  8. // @grant GM_getValue
  9. // @grant GM_setValue
  10. // @run-at document-start
  11. // @namespace https://gf.qytechs.cn/users/410786
  12. // ==/UserScript==
  13.  
  14. (function(){
  15.  
  16. if(location.pathname.startsWith("/contest/")){
  17. window.addEventListener("DOMContentLoaded", function(){
  18. // Stores tutorial links. Sometimes it's not linked in some old contests, see https://codeforces.com/blog/entry/7749?locale=en
  19. for(const element of document.querySelectorAll(".roundbox ul li a[href*='/blog/entry/'"))
  20. if(element.innerText.match(/Tutorial|Разбор задач/))
  21. GM_setValue("isTutorial"+element.href.match(/\/blog\/entry\/(\d+)/)[1], true)
  22. })
  23. return
  24. }
  25.  
  26.  
  27.  
  28. function wrappedInSpoiler(node){
  29. while(node!==null){
  30. if(node.classList && node.classList.contains("spoiler")) return true;
  31. node=node.parentNode;
  32. }
  33. return false;
  34. }
  35.  
  36. var newStyle=false
  37.  
  38. function wrapInSpoiler(nodes, spoilerTitle){
  39. if(!Array.isArray(nodes)) nodes=[nodes]
  40. if(nodes.length==0) return
  41.  
  42. const spoilerElement=document.createElement("div")
  43. spoilerElement.classList.add("spoiler")
  44. spoilerElement.innerHTML='<b class="spoiler-title"></b><div class="spoiler-content" style="display: none;"></div>'
  45. spoilerElement.firstElementChild.innerText=spoilerTitle
  46.  
  47. //console.log("Wrapping in spoiler: ", nodes)
  48. //nodes[0].insertAdjacentElement('beforebegin', spoilerElement);
  49. nodes[0].parentNode.insertBefore(spoilerElement, nodes[0]);
  50. nodes.forEach(function(node){
  51. spoilerElement.lastElementChild.appendChild(node) // "If the given child is a reference to an existing node in the document, appendChild() moves it from its current position to the new position"
  52. })
  53. }
  54.  
  55. function wrapOldStyle(){
  56. //const headerSelector="h2,h3,a[href^='/contest'][href*='/problem/']"
  57. const headerSelector="h1,h2,h3,hr"
  58. for(const element of document.getElementsByClassName("content")[0].querySelectorAll(headerSelector)){
  59. const elements=[]
  60. let tmp=element.nextSibling
  61. while(tmp!==null && ((tmp instanceof Text) || !tmp.matches(headerSelector))){
  62. elements.push(tmp)
  63. tmp=tmp.nextSibling
  64. }
  65. wrapInSpoiler(elements, "Tutorial")
  66. }
  67. }
  68.  
  69. const observer=new MutationObserver(function(mutationList, observer){
  70. for(const mutation of mutationList){
  71. for(const node of mutation.addedNodes){
  72. if(node instanceof Element && node.matches("div.roundbox.meta")){
  73. if(GM_getValue("isTutorial"+location.href.match(/\/blog\/entry\/(\d+)/)[1])){
  74. if(!newStyle) wrapOldStyle()
  75. }
  76. observer.disconnect()
  77. return
  78. }
  79.  
  80. if(
  81. node.tagName==="SPAN" && node.style.padding==="0px 0.35em" &&
  82. node.firstChild instanceof Text &&
  83. ["Tutorial of ", "Разбор задач "].includes(node.firstChild.nodeValue)
  84. //node.previousElementSibling.tagName==="IMG" && node.previousElementSibling.src.includes("paperclip")
  85. ){
  86. if(!newStyle) wrapOldStyle()
  87. observer.disconnect()
  88. return
  89. }
  90.  
  91. if(node.classList!==undefined && node.classList.contains("problemTutorial")){
  92. newStyle=true
  93. if(!wrappedInSpoiler(node)){
  94. var spoilerTitle='Tutorial'
  95. const problemcode=node.getAttribute("problemcode")
  96. if(problemcode) spoilerTitle+=' - '+problemcode
  97.  
  98. wrapInSpoiler(node, spoilerTitle)
  99. }
  100. }
  101. }
  102. }
  103. })
  104. observer.observe(document, { childList: true, subtree: true });
  105.  
  106.  
  107.  
  108. })()

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址