GitHub Code Colors

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

目前为 2017-10-08 提交的版本。查看 最新版本

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