GitHub Code Colors

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

当前为 2016-08-20 提交的版本,查看 最新版本

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