GitHub Code Colors

A userscript that adds a color swatch next to the code color definition

目前为 2018-05-17 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name GitHub Code Colors
  3. // @version 1.1.16
  4. // @description A userscript that adds a color swatch next to the code color definition
  5. // @license MIT
  6. // @author Rob Garrison
  7. // @namespace https://github.com/Mottie
  8. // @include https://github.com/*
  9. // @run-at document-idle
  10. // @grant GM.addStyle
  11. // @grant GM_addStyle
  12. // @require https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js?updated=20180103
  13. // @require https://greasyfork.org/scripts/28721-mutations/code/mutations.js?version=597950
  14. // @icon https://assets-cdn.github.com/pinned-octocat.svg
  15. // ==/UserScript==
  16. (() => {
  17. "use strict";
  18.  
  19. GM.addStyle(`
  20. .ghcc-block { width:12px; height:12px; display:inline-block;
  21. vertical-align:middle; margin-right:4px; border:1px solid #555; }
  22. `);
  23.  
  24. const namedColors = [
  25. "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
  26. "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
  27. "burlywood", "cadetblue", "chartreuse", "chocolate", "coral",
  28. "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue", "darkcyan",
  29. "darkgoldenrod", "darkgray", "darkgrey", "darkgreen", "darkkhaki",
  30. "darkmagenta", "darkolivegreen", "darkorange", "darkorchid", "darkred",
  31. "darksalmon", "darkseagreen", "darkslateblue", "darkslategray",
  32. "darkslategrey", "darkturquoise", "darkviolet", "deeppink", "deepskyblue",
  33. "dimgray", "dimgrey", "dodgerblue", "firebrick", "floralwhite",
  34. "forestgreen", "fuchsia", "gainsboro", "ghostwhite", "gold", "goldenrod",
  35. "gray", "grey", "green", "greenyellow", "honeydew", "hotpink",
  36. "indianred", "indigo", "ivory", "khaki", "lavender", "lavenderblush",
  37. "lawngreen", "lemonchiffon", "lightblue", "lightcoral", "lightcyan",
  38. "lightgoldenrodyellow", "lightgray", "lightgrey", "lightgreen",
  39. "lightpink", "lightsalmon", "lightseagreen", "lightskyblue",
  40. "lightslategray", "lightslategrey", "lightsteelblue", "lightyellow",
  41. "lime", "limegreen", "linen", "magenta", "maroon", "mediumaquamarine",
  42. "mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen",
  43. "mediumslateblue", "mediumspringgreen", "mediumturquoise",
  44. "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin",
  45. "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange",
  46. "orangered", "orchid", "palegoldenrod", "palegreen", "paleturquoise",
  47. "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum",
  48. "powderblue", "purple", "rebeccapurple", "red", "rosybrown", "royalblue",
  49. "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell", "sienna",
  50. "silver", "skyblue", "slateblue", "slategray", "slategrey", "snow",
  51. "springgreen", "steelblue", "tan", "teal", "thistle", "tomato",
  52. "turquoise", "violet", "wheat", "white", "whitesmoke", "yellow",
  53. "yellowgreen"
  54. ].join("|"),
  55.  
  56. // don't use a div, because GitHub-Dark adds a :hover background
  57. // color definition on divs
  58. block = document.createElement("span");
  59. block.className = "ghcc-block";
  60.  
  61. function addNode(el, val) {
  62. const node = block.cloneNode();
  63. node.style.backgroundColor = val;
  64. // don't add node if color is invalid
  65. if (node.style.backgroundColor !== "") {
  66. el.insertBefore(node, el.childNodes[0]);
  67. }
  68. }
  69.  
  70. function getTextContent(el) {
  71. return el ? el.textContent : "";
  72. }
  73.  
  74. function addColors() {
  75. if (document.querySelector(".highlight")) {
  76. let indx = 0;
  77. const regexNamed = new RegExp("^(" + namedColors + ")$", "i"),
  78. // #123, #123456 or 0x123456 (unix style colors, used by three.js)
  79. regexHex = /^(#|0x)([0-9A-F]{6,8}|[0-9A-F]{3,4})$/i,
  80. // rgb(0,0,0) or rgba(0,0,0,0.2)
  81. regexRGB = /^rgba?(\([^\)]+\))?/i,
  82. regexRGBA = /rgba/i,
  83. // hsl(0,0%,0%) or hsla(0,0%,0%,0.2);
  84. regexHSL = /^hsla?(\([^\)]+\))?/i,
  85.  
  86. // misc regex
  87. regexQuotes = /['"]/g,
  88. regexUnix = /^0x/,
  89. regexPercent = /%%/g,
  90.  
  91. // .pl-c1 targets css hex colors, "rgb" and "hsl"
  92. els = document.querySelectorAll(".pl-c1, .pl-s"),
  93. len = els.length;
  94.  
  95. // loop with delay to allow user interaction
  96. const loop = () => {
  97. let el, txt, tmp, indx2,
  98. // max number of DOM insertions per loop
  99. max = 0;
  100. while (max < 20 && indx < len) {
  101. if (indx >= len) {
  102. return;
  103. }
  104. el = els[indx];
  105. txt = el.textContent;
  106. if (el.classList.contains("pl-s")) {
  107. txt = txt.replace(regexQuotes, "");
  108. } else if (el.parentNode.classList.contains("pl-c1")) {
  109. // ignore nested pl-c1 (see https://git.io/vFx8y)
  110. indx++;
  111. continue;
  112. }
  113. if (regexHex.test(txt) || regexNamed.test(txt)) {
  114. if (!el.querySelector(".ghcc-block")) {
  115. addNode(el, txt.replace(regexUnix, "#"));
  116. max++;
  117. }
  118. } else if (regexRGB.test(txt)) {
  119. if (!el.querySelector(".ghcc-block")) {
  120. // color in a string contains everything
  121. if (el.classList.contains("pl-s")) {
  122. txt = txt.match(regexRGB)[0];
  123. } else {
  124. // rgb(a) colors contained in multiple "pl-c1" spans
  125. indx2 = regexRGBA.test(txt) ? 4 : 3;
  126. tmp = [];
  127. while (indx2) {
  128. tmp.push(getTextContent(els[++indx]));
  129. indx2--;
  130. }
  131. txt += "(" + tmp.join(",") + ")";
  132. }
  133. addNode(el, txt);
  134. max++;
  135. }
  136. } else if (regexHSL.test(txt)) {
  137. if (!el.querySelector(".ghcc-block")) {
  138. tmp = /a$/i.test(txt);
  139. if (el.classList.contains("pl-s")) {
  140. // color in a string contains everything
  141. txt = txt.match(regexHSL)[0];
  142. } else {
  143. // traverse this HTML... & els only contains the pl-c1 nodes
  144. // <span class="pl-c1">hsl</span>(<span class="pl-c1">1</span>,
  145. // <span class="pl-c1">1</span><span class="pl-k">%</span>,
  146. // <span class="pl-c1">1</span><span class="pl-k">%</span>);
  147. // using getTextContent in case of invalid css
  148. txt = txt + "(" + getTextContent(els[++indx]) + "," +
  149. getTextContent(els[++indx]) + "%," +
  150. // hsla needs one more parameter
  151. getTextContent(els[++indx]) + "%" +
  152. (tmp ? "," + getTextContent(els[++indx]) : "") + ")";
  153. }
  154. // sometimes (previews only?) the .pl-k span is nested inside
  155. // the .pl-c1 span, so we end up with "%%"
  156. addNode(el, txt.replace(regexPercent, "%"));
  157. max++;
  158. }
  159. }
  160. indx++;
  161. }
  162. if (indx < len) {
  163. setTimeout(() => {
  164. loop();
  165. }, 200);
  166. }
  167. };
  168. loop();
  169. }
  170. }
  171.  
  172. document.addEventListener("ghmo:container", addColors);
  173. document.addEventListener("ghmo:preview", addColors);
  174. addColors();
  175.  
  176. })();