Greasy Fork 支持 简体中文。

GitHub Toggle Code Wrap

A userscript that adds a code wrap toggle button

目前為 2018-12-19 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name GitHub Toggle Code Wrap
  3. // @version 1.1.9
  4. // @description A userscript that adds a code wrap toggle button
  5. // @license MIT
  6. // @author StylishThemes
  7. // @namespace https://github.com/StylishThemes
  8. // @include https://github.com/*
  9. // @include https://gist.github.com/*
  10. // @run-at document-idle
  11. // @grant GM_registerMenuCommand
  12. // @grant GM_getValue
  13. // @grant GM_setValue
  14. // @grant GM_addStyle
  15. // @require https://greasyfork.org/scripts/28721-mutations/code/mutations.js?version=634242
  16. // @icon https://avatars3.githubusercontent.com/u/6145677?v=3&s=200
  17. // ==/UserScript==
  18. /* jshint esnext:true, unused:true */
  19. (() => {
  20. "use strict";
  21. /*
  22. This code is also part of the GitHub-Dark Script
  23. (https://github.com/StylishThemes/GitHub-Dark-Script)
  24. Extracted out into a separate userscript in case users only want
  25. to add this functionality
  26. */
  27. // set by GM popup menu
  28. let globalWrap = GM_getValue("github-global-code-wrap", true),
  29. busy = false;
  30.  
  31. const wrapIcon = `
  32. <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 768 768">
  33. <path d="M544.5 352.5q52.5 0 90 37.5t37.5 90-37.5 90-90 37.5H480V672l-96-96 96-96v64.5h72q25.5 0 45-19.5t19.5-45-19.5-45-45-19.5H127.5v-63h417zm96-192v63h-513v-63h513zm-513 447v-63h192v63h-192z"/>
  34. </svg>`,
  35.  
  36. // inline code wrap css
  37. wrapCss = {
  38. "wrapped": "white-space: pre-wrap !important; word-break: break-all !important; overflow-wrap: break-word !important; display: block !important;",
  39. "unwrap": "white-space: pre !important; word-break: normal !important; display: block !important;"
  40. };
  41.  
  42. function findWrap(event) {
  43. const target = event.target;
  44. if (target.classList.contains("ghd-wrap-toggle")) {
  45. toggleClasses(target);
  46. }
  47. }
  48.  
  49. function findSibling(node, selector) {
  50. node = node.parentNode.firstElementChild;
  51. while ((node = node.nextElementSibling)) {
  52. if (node.matches(selector)) {
  53. return node;
  54. }
  55. }
  56. return null;
  57. }
  58.  
  59. function toggleClasses(button) {
  60. let css,
  61. target = findSibling(button, "code, pre, .highlight, .diff-table");
  62. if (!target) {
  63. console.error("Code wrap icon associated code not found", button);
  64. return;
  65. }
  66. // code with line numbers
  67. if (target.nodeName === "TABLE") {
  68. if (target.className.indexOf("wrap-table") < 0) {
  69. css = !globalWrap;
  70. } else {
  71. css = target.classList.contains("ghd-unwrap-table");
  72. }
  73. target.classList.toggle("ghd-wrap-table", css);
  74. target.classList.toggle("ghd-unwrap-table", !css);
  75. button.classList.toggle("wrapped", css);
  76. button.classList.toggle("unwrap", !css);
  77. } else {
  78. css = target.getAttribute("style") || "";
  79. if (css === "") {
  80. css = wrapCss[globalWrap ? "unwrap" : "wrapped"];
  81. } else {
  82. css = wrapCss[css === wrapCss.wrapped ? "unwrap" : "wrapped"];
  83. }
  84. target.setAttribute("style", css);
  85. button.classList.toggle("wrapped", css === wrapCss.wrapped);
  86. button.classList.toggle("unwrap", css === wrapCss.wrapped);
  87. }
  88. }
  89.  
  90. function addCodeWrapButton(button, target) {
  91. target.insertBefore(button.cloneNode(true), target.childNodes[0]);
  92. target.classList.add("ghd-code-wrapper");
  93. }
  94.  
  95. // Add code wrap toggle
  96. function buildCodeWrap() {
  97. if (busy) {
  98. return;
  99. }
  100. busy = true;
  101.  
  102. // add wrap code buttons
  103. let wrapper = $$(".blob-wrapper"),
  104. indx = wrapper ? wrapper.length : 0;
  105. const button = document.createElement("button");
  106. button.className = "ghd-wrap-toggle tooltipped tooltipped-sw btn btn-sm" +
  107. (globalWrap ? "" : " unwrap");
  108. button.setAttribute("aria-label", "Toggle code wrap");
  109. button.innerHTML = wrapIcon;
  110.  
  111. // Code in table with line numbers
  112. while (indx--) {
  113. if (!$(".ghd-wrap-toggle", wrapper[indx])) {
  114. addCodeWrapButton(button, wrapper[indx]);
  115. }
  116. }
  117.  
  118. // Code in markdown comments & wiki pages
  119. wrapper = $$(`
  120. .markdown-body pre:not(.ghd-code-wrapper),
  121. .markdown-format pre:not(.ghd-code-wrapper)`
  122. );
  123. indx = wrapper ? wrapper.length : 0;
  124. while (indx--) {
  125. const pre = wrapper[indx];
  126. const code = $("code", pre);
  127. const wrap = pre.parentNode;
  128. if (code) {
  129. addCodeWrapButton(button, pre);
  130. } else if (wrap.classList.contains("highlight")) {
  131. addCodeWrapButton(button, wrap);
  132. }
  133. }
  134. busy = false;
  135. }
  136.  
  137. function init() {
  138. document.addEventListener("click", findWrap);
  139. $("body").classList.toggle("nowrap", !globalWrap);
  140. buildCodeWrap();
  141. }
  142.  
  143. function $(str, el) {
  144. return (el || document).querySelector(str);
  145. }
  146.  
  147. function $$(str, el) {
  148. return [...(el || document).querySelectorAll(str)];
  149. }
  150.  
  151. // don't initialize if GitHub Dark Script is active
  152. if (!$("#ghd-menu")) {
  153. GM_addStyle(`
  154. /* icons next to a pre */
  155. .ghd-wrap-toggle {
  156. padding: 3px 5px;
  157. position: absolute;
  158. right: 3px;
  159. top: 3px;
  160. -moz-user-select: none;
  161. -webkit-user-select: none;
  162. cursor: pointer;
  163. z-index: 20;
  164. }
  165. .ghd-code-wrapper:not(:hover) .ghd-wrap-toggle {
  166. border-color: transparent !important;
  167. background: transparent !important;
  168. }
  169. /* file & diff code tables */
  170. body .ghd-wrap-table td.blob-code-inner {
  171. white-space: pre-wrap !important;
  172. word-break: break-all !important;
  173. }
  174. body .ghd-unwrap-table td.blob-code-inner {
  175. white-space: pre !important;
  176. word-break: normal !important;
  177. }
  178. /* icons for non-syntax highlighted code blocks;
  179. * see https://github.com/gjtorikian/html-proofer/blob/master/README.md
  180. */
  181. .markdown-body:not(.comment-body) .ghd-wrap-toggle:not(:first-child) {
  182. right: 3.4em;
  183. }
  184. .ghd-wrap-toggle svg {
  185. height: 14px;
  186. width: 14px;
  187. fill: rgba(110, 110, 110, .4);
  188. pointer-events: none;
  189. vertical-align: text-bottom;
  190. }
  191. .ghd-code-wrapper:hover .ghd-wrap-toggle.unwrap svg,
  192. .ghd-code-wrapper:hover .ghd-wrap-toggle svg {
  193. fill: #8b0000; /* wrap disabled (red) */
  194. }
  195. body:not(.nowrap) .ghd-code-wrapper:hover .ghd-wrap-toggle:not(.unwrap) svg,
  196. .ghd-code-wrapper:hover .ghd-wrap-toggle.wrapped svg {
  197. fill: #006400; /* wrap enabled (green) */
  198. }
  199. .blob-wrapper, .markdown-body pre, .markdown-body .highlight,
  200. .ghd-code-wrapper {
  201. position: relative;
  202. }
  203. /* global code wrap */
  204. body:not(.nowrap) .blob-code-inner:not(.blob-code-hunk),
  205. body:not(.nowrap) .markdown-body pre > code,
  206. body:not(.nowrap) .markdown-body .highlight > pre {
  207. white-space: pre-wrap !important;
  208. word-break: break-all !important;
  209. overflow-wrap: break-word !important;
  210. display: block !important;
  211. }
  212. td.blob-code-inner {
  213. display: table-cell !important;
  214. }
  215. `);
  216.  
  217. document.addEventListener("ghmo:container", buildCodeWrap);
  218. document.addEventListener("ghmo:preview", buildCodeWrap);
  219.  
  220. // Add GM options
  221. GM_registerMenuCommand("Set Global Code Wrap Option", () => {
  222. const body = $("body"),
  223. val = prompt("Global Code Wrap (true/false):", "" + globalWrap);
  224. globalWrap = /^t/.test(val);
  225. GM_setValue("github-global-code-wrap", globalWrap);
  226. body.classList.toggle("nowrap", !globalWrap);
  227. });
  228.  
  229. init();
  230. }
  231.  
  232. })();