Syntaxify

Universal syntax highlighting

目前为 2015-06-25 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Syntaxify
  3. // @description Universal syntax highlighting
  4. // @namespace http://rob-bolton.co.uk
  5. // @version 1.3
  6. // @include http*
  7. // @grant GM_addStyle
  8. // @grant GM_getResourceText
  9. // @require http://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.6/highlight.min.js
  10. // @resource highlightJsCss https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.6/styles/monokai.min.css
  11. // ==/UserScript==
  12. //
  13.  
  14. var tagsToSearch = ["pre", "code"];
  15.  
  16. GM_addStyle(GM_getResourceText("highlightJsCss"));
  17.  
  18. var codeBlocks = {};
  19. var itemCounter = 0;
  20. var selectedItem;
  21.  
  22. function isCodeBlock(node) {
  23. if(node) {
  24. var tagname = node.tagName.toLowerCase();
  25. for(var i=0; i<tagsToSearch.length; i++) {
  26. if(tagname == tagsToSearch[i]) {
  27. return true;
  28. }
  29. }
  30. }
  31. return false;
  32. }
  33.  
  34. function wrapSelection() {
  35. var selection = window.getSelection();
  36. if(selection.rangeCount && tagsToSearch.indexOf(selection.anchorNode.nodeName) == -1) {
  37. range = selection.getRangeAt(0);
  38. if(range) {
  39. range.surroundContents(new CodeContainer());
  40. }
  41. }
  42. }
  43.  
  44. function CodeContainer() {
  45. var container = document.createElement("code");
  46. var menu = addSyntaxMenuForNode(container);
  47. var menuItem = document.createElement("menuitem");
  48. menuItem.setAttribute("label", "Unwrap code");
  49. menuItem.addEventListener("click", function(){
  50. var parent = container.parentNode;
  51. var newTextNode = document.createTextNode(container.textContent);
  52. parent.insertBefore(newTextNode, container);
  53. parent.removeChild(container);
  54. });
  55. menu.appendChild(menuItem);
  56. return container;
  57. }
  58.  
  59. function addBlock(node) {
  60. if(!node.id) {
  61. node.id = "SyntaxifyBlock" + itemCounter++;
  62. }
  63. codeBlocks[node.id] = {
  64. "node": node,
  65. "highlighted": false,
  66. "originalNode": node.cloneNode()
  67. }
  68. }
  69.  
  70. function revert(nodeData) {
  71. var parent = nodeData.node.parentNode;
  72. parent.insertBefore(nodeData.originalNode, nodeData.node);
  73. parent.removeChild(nodeData.node);
  74. nodeData.node = nodeData.originalNode;
  75. nodeData.highlighted = false;
  76. nodeData.node.setAttribute("contextMenu", "SyntaxifyPreMenu");
  77. }
  78.  
  79. function highlight() {
  80. var node = selectedItem;
  81. if(node) {
  82. if(!codeBlocks[node.id]) {
  83. addBlock(node);
  84. }
  85. var nodeData = codeBlocks[node.id];
  86. if(nodeData.highlighted === false) {
  87. nodeData.originalNode = node.cloneNode(true);
  88. try {
  89. if(nodeData.lang) {
  90. node.className = (node.className || "") + " lang-" + nodeData.lang;
  91. }
  92. hljs.highlightBlock(node);
  93. } catch(e) {
  94. console.err(e);
  95. revert(nodeData);
  96. alert(e);
  97. return;
  98. }
  99. nodeData.highlighted = true;
  100. node.setAttribute("contextMenu", "SyntaxifyPostMenu");
  101. }
  102. }
  103. }
  104.  
  105. function highlightAs() {
  106. var node = selectedItem;
  107. if(node) {
  108. if(!codeBlocks[node.id]) {
  109. addBlock(node);
  110. }
  111. var lang = prompt("Language:");
  112. if(lang) {
  113. codeBlocks[node.id].lang = lang;
  114. highlight();
  115. } else {
  116. codeBlocks[node.id].lang = null;
  117. }
  118. }
  119. }
  120.  
  121. function unHighlight() {
  122. var node = selectedItem;
  123. if(node) {
  124. if(!codeBlocks[node.id]) {
  125. addBlock(node);
  126. }
  127. var nodeData = codeBlocks[node.id];
  128. if(nodeData.highlighted === true) {
  129. revert(nodeData);
  130. }
  131. }
  132. }
  133.  
  134. var syntaxableElements = [];
  135. for(var i=0; i<tagsToSearch.length; i++) {
  136. var tagsFound = document.getElementsByTagName(tagsToSearch[i]);
  137. for(var j=0; j<tagsFound.length; j++) {
  138. syntaxableElements.push(tagsFound.item(j));
  139. }
  140. }
  141.  
  142. if(syntaxableElements) {
  143. for(var i=0; i<(syntaxableElements.length || 0); i++) {
  144. syntaxableElements[i].setAttribute("contextmenu", "SyntaxifyPreMenu");
  145. }
  146. }
  147.  
  148. var body = document.body;
  149. var bodyMenu;
  150. var bodyMenuId = body.getAttribute("contextmenu");
  151. if(!bodyMenuId) {
  152. bodyMenu = document.createElement("menu");
  153. bodyMenu.setAttribute("type", "context");
  154. bodyMenu.setAttribute("id", "SyntaxifyMenuMain");
  155. } else {
  156. bodyMenu = document.getElementById(bodyMenuId);
  157. }
  158.  
  159. var wrapItem = document.createElement("menuitem");
  160. wrapItem.setAttribute("label", "Syntaxify - Wrap with <code>");
  161. wrapItem.addEventListener("click", wrapSelection, false);
  162.  
  163. bodyMenu.appendChild(wrapItem);
  164. body.appendChild(bodyMenu);
  165. body.setAttribute("contextmenu", bodyMenu.getAttribute("id"));
  166.  
  167.  
  168. var syntaxPreMenu = document.createElement("menu");
  169. syntaxPreMenu.setAttribute("type", "context");
  170. syntaxPreMenu.setAttribute("id", "SyntaxifyPreMenu");
  171.  
  172. var syntaxPreMenuHighlightItem = document.createElement("menuitem");
  173. syntaxPreMenuHighlightItem.setAttribute("label", "Syntaxify - Highlight");
  174. syntaxPreMenuHighlightItem.addEventListener("click", highlight, false);
  175. syntaxPreMenu.appendChild(syntaxPreMenuHighlightItem);
  176.  
  177. var syntaxPreMenuHighlightAsItem = document.createElement("menuitem");
  178. syntaxPreMenuHighlightAsItem.setAttribute("label", "Syntaxify - Highlight as...");
  179. syntaxPreMenuHighlightAsItem.addEventListener("click", highlightAs, false);
  180. syntaxPreMenu.appendChild(syntaxPreMenuHighlightAsItem);
  181.  
  182. body.appendChild(syntaxPreMenu);
  183.  
  184.  
  185. var syntaxPostMenu = document.createElement("menu");
  186. syntaxPostMenu.setAttribute("type", "context");
  187. syntaxPostMenu.setAttribute("id", "SyntaxifyPostMenu");
  188.  
  189. var syntaxPostMenuUnHighlightItem = document.createElement("menuitem");
  190. syntaxPostMenuUnHighlightItem.setAttribute("label", "Syntaxify - UnHighlight");
  191. syntaxPostMenuUnHighlightItem.addEventListener("click", unHighlight, false);
  192. syntaxPostMenu.appendChild(syntaxPostMenuUnHighlightItem);
  193.  
  194. body.appendChild(syntaxPostMenu);
  195.  
  196. document.addEventListener("mousedown", function(event) {
  197. if(event.button == 2) {
  198. var node = event.target;
  199. while(node.parentNode && !isCodeBlock(node)) {
  200. node = node.parentNode;
  201. }
  202. if(isCodeBlock(node)) {
  203. selectedItem = node;
  204. } else {
  205. selectedItem = null;
  206. }
  207. }
  208. });