代码片段高亮

选择代码片段后点击图标弹出新窗口显示语法高亮美化与格式化后的代码与字数统计

  1. // ==UserScript==
  2. // @name Highlight Every Code
  3. // @name:zh-CN 代码片段高亮
  4. // @name:zh-TW 程式碼片斷高亮
  5. // @namespace hoothin
  6. // @version 2.2.3.1
  7. // @description Add a icon to popup a window that allows syntax highlighting and beautify and word count of source code snippets on current page
  8. // @description:zh-CN 选择代码片段后点击图标弹出新窗口显示语法高亮美化与格式化后的代码与字数统计
  9. // @description:zh-TW 選擇程式碼片段後點選圖示彈出新視窗顯示語法高亮美化與格式化後的程式碼與字數統計
  10. // @author Hoothin
  11. // @grant GM_registerMenuCommand
  12. // @grant GM.registerMenuCommand
  13. // @grant GM_setValue
  14. // @grant GM.setValue
  15. // @grant GM_getValue
  16. // @grant GM.getValue
  17. // @grant unsafeWindow
  18. // @compatible chrome
  19. // @compatible firefox
  20. // @license MIT License
  21. // @contributionURL https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=rixixi@sina.com&item_name=Greasy+Fork+donation
  22. // @contributionAmount 1
  23. // @include *
  24. // ==/UserScript==
  25.  
  26. (function() {
  27. 'use strict';
  28. var codeIcon=document.createElement("img");
  29. var codes, selStr, scrollX, scrollY, customInput=false,altKey=true,ctrlKey=true,shiftKey=true,metaKey=true,hiding=false;
  30. var _unsafeWindow=(typeof unsafeWindow=='undefined'? window : unsafeWindow);
  31. codeIcon.className="codeIcon";
  32. codeIcon.style.opacity=0;
  33. codeIcon.title="Show this code snippet";
  34. codeIcon.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAYAgMAAACD0OXYAAAACVBMVEX7+/swMDBTU1MLxgsCAAAAJElEQVQI12MIBYEAGLUKBBbAqAUMQICgAoAqoBQ95JaCnASjAAgXMdk3d5HTAAAAAElFTkSuQmCC";
  35. codeIcon.onmousedown=highlight;
  36. var style = document.createElement('style');
  37. style.textContent = `
  38. .codeIcon{
  39. position:fixed;
  40. z-index:99999;
  41. cursor:pointer;
  42. transition:opacity 0.3s ease-in-out 0s;
  43. opacity:0.3;
  44. border:5px solid rgba(0, 0, 0, 0.2);
  45. border-radius:10px;
  46. max-width:30px;
  47. max-height:30px;
  48. overflow:hidden;
  49. }
  50. .codeIcon:hover{
  51. opacity:0.9;
  52. }
  53. `;
  54. style.type = 'text/css';
  55. document.head.appendChild(style);
  56.  
  57. document.addEventListener('DOMMouseScroll', function(o) {
  58. hideIcon();
  59. });
  60. document.addEventListener('wheel', function(o) {
  61. hideIcon();
  62. });
  63. document.addEventListener('mousewheel', function(o) {
  64. hideIcon();
  65. });
  66. document.addEventListener('mouseover', function(o) {
  67. if(hiding)return;
  68. var target=o.target,hasCode=false;
  69. while(target && target.nodeName!="BODY"){
  70. if(target.nodeName=="PRE" || target.nodeName=="CODE"){
  71. hasCode=true;
  72. break;
  73. }
  74. target=target.parentNode;
  75. }
  76. if(!hasCode)return;
  77. if(target.offsetWidth && target.offsetWidth<110)return;
  78. selStr=target.innerText;
  79. if(!selStr)return;
  80. codes=selStr.replace(/&/g, "&amp;").replace(/\</g,"&lt;").replace(/\>/g,"&gt;");
  81. document.body.appendChild(codeIcon);
  82. let pos=getMousePos(o);
  83. scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
  84. scrollY = document.documentElement.scrollTop || document.body.scrollTop;
  85. let top=target.offsetTop-scrollY;
  86. let left=target.offsetLeft-scrollX;
  87. codeIcon.style.opacity="";
  88. codeIcon.style.top=top+"px";
  89. codeIcon.style.left=left+"px";
  90. });
  91. document.addEventListener('mousedown', function(o) {
  92. hiding=true;
  93. setTimeout(()=>{hiding=false},1000);
  94. hideIcon();
  95. });
  96. document.addEventListener('mouseup', function(o) {
  97. if (o.button === 0 && ((!ctrlKey && !altKey && !metaKey && !shiftKey) || (ctrlKey && o.ctrlKey) || (altKey && o.altKey) || (metaKey && o.metaKey) || (shiftKey && o.shiftKey))) {
  98. //var customInputKey=(o.ctrlKey && o.shiftKey);
  99. setTimeout(function(){
  100. selStr=document.getSelection().toString();
  101. codes=selStr.replace(/&/g, "&amp;").replace(/\</g,"&lt;").replace(/\>/g,"&gt;");
  102. if(!codes){
  103. return;
  104. }
  105. document.body.appendChild(codeIcon);
  106. let pos=getMousePos(o);
  107. let clientH=(document.documentElement && document.documentElement.clientHeight) || 0;
  108. let clientW=(document.documentElement && document.documentElement.clientWidth) || 0;
  109. let top=pos.y>clientH-50?(pos.y-30):(pos.y+20);
  110. let left=pos.x>clientW-50?(pos.x-30):(pos.x+20);
  111. codeIcon.style.opacity="";
  112. codeIcon.style.top=top+"px";
  113. codeIcon.style.left=left+"px";
  114. },1);
  115. }
  116. },false);
  117.  
  118. function highlight(){
  119. if(customInput){
  120. selStr=prompt("Input code here","");
  121. if(!selStr)return;
  122. codes=selStr.replace(/&/g, "&amp;").replace(/\</g,"&lt;").replace(/\>/g,"&gt;");
  123. }
  124. let html='<title>Code Snippet</title>'+
  125. '<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prettify/r298/prettify.min.css"/>'+
  126. '<script>var code,codeStr;window.onload=function(){code=document.querySelector("#code");codeStr=code.innerHTML.replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/&(nbsp;|amp;|#39;|quot;)/g, "&amp;$1");prettyPrint();'+
  127. 'document.querySelector("#js").onclick=function(){'+
  128. 'code.innerHTML=js_beautify('+
  129. 'codeStr.replace(/&gt;/g, \'>\').replace(/&lt;/g, \'<\').replace(/\'(\\\\\'|[^\'])*?\'/g, function(word){'+
  130. 'return word.replace(/>/g, \'&gt;\').replace(/</g, \'&lt;\');}'+
  131. ').replace(/\"(\\\\\"|[^\"])*?\"/g, function(word){'+
  132. 'return word.replace(/>/g, \'&gt;\').replace(/</g, \'&lt;\');}'+
  133. '));code.className=\'prettyprint linenums\';prettyPrint();return false;'+
  134. '};}</script>'+
  135. '<script src="https://cdnjs.cloudflare.com/ajax/libs/prettify/r298/prettify.min.js?skin=sons-of-obsidian"></script>'+
  136. '<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.6.4/beautify.min.js"></script>'+
  137. '<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.6.4/beautify-html.min.js"></script>'+
  138. '<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.6.4/beautify-css.min.js"></script>'+
  139. 'Code formatting: <a id="js" href="#">Javaspcript</a> '+
  140. '<a href="#" onclick="code.innerHTML=html_beautify(codeStr);code.className=\'prettyprint linenums\';prettyPrint();return false;">Html</a> '+
  141. '<a href="#" onclick="code.innerHTML=css_beautify(codeStr);code.className=\'prettyprint linenums\';prettyPrint();return false;">Css</a> '+
  142. '<a href="#" onclick="code.innerHTML=codeStr;code.className=\'prettyprint linenums\';prettyPrint();return false;">Raw</a> <b style="color:red">('+selStr.replace(/\s/g,"").length+' words)</b>'+
  143. '<pre id="code" class="prettyprint linenums" style="word-wrap: break-word; white-space: pre-wrap;border: 1px solid rgb(136, 136, 204);border-radius: 8px;">' + codes + "</pre>";
  144.  
  145. let c = _unsafeWindow.open("", "_blank", "width=750, height=400, location=0, resizable=1, menubar=0, scrollbars=0");
  146. c.document.write(html);
  147. c.document.close();
  148. }
  149. function hideIcon(){
  150. codeIcon.style.opacity=0;
  151. customInput=false;
  152. if(codeIcon.parentNode)codeIcon.parentNode.removeChild(codeIcon);
  153. }
  154. function getMousePos(event) {
  155. var e = event || window.event;
  156. scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
  157. scrollY = document.documentElement.scrollTop || document.body.scrollTop;
  158. var x = (e.pageX || e.clientX) - scrollX;
  159. var y = (e.pageY || e.clientY) - scrollY;
  160. return { 'x': x, 'y': y };
  161. }
  162.  
  163. var _GM_registerMenuCommand;
  164. if(typeof GM_registerMenuCommand!='undefined'){
  165. _GM_registerMenuCommand=GM_registerMenuCommand;
  166. }else if(typeof GM!='undefined' && typeof GM.registerMenuCommand!='undefined'){
  167. _GM_registerMenuCommand=GM.registerMenuCommand;
  168. }
  169. if(typeof _GM_registerMenuCommand=='undefined')_GM_registerMenuCommand=(s,f)=>{};
  170. var storage={
  171. supportGM: typeof GM_getValue=='function' && typeof GM_getValue('a','b')!='undefined',
  172. supportGMPromise: typeof GM!='undefined' && typeof GM.getValue=='function' && typeof GM.getValue('a','b')!='undefined',
  173. mxAppStorage:(function(){
  174. try{
  175. return window.external.mxGetRuntime().storage;
  176. }catch(e){
  177. };
  178. })(),
  179. operaUJSStorage:(function(){
  180. try{
  181. return window.opera.scriptStorage;
  182. }catch(e){
  183. };
  184. })(),
  185. setItem:function(key,value){
  186. if(this.operaUJSStorage){
  187. this.operaUJSStorage.setItem(key,value);
  188. }else if(this.mxAppStorage){
  189. this.mxAppStorage.setConfig(key,value);
  190. }else if(this.supportGM){
  191. GM_setValue(key,value);
  192. }else if(this.supportGMPromise){
  193. GM.setValue(key,value);
  194. }else if(window.localStorage){
  195. window.localStorage.setItem(key,value);
  196. };
  197. },
  198. getItem:function(key,cb){
  199. var value;
  200. if(this.operaUJSStorage){
  201. value=this.operaUJSStorage.getItem(key);
  202. }else if(this.mxAppStorage){
  203. value=this.mxAppStorage.getConfig(key);
  204. }else if(this.supportGM){
  205. value=GM_getValue(key);
  206. }else if(this.supportGMPromise){
  207. value=GM.getValue(key).then(v=>{cb(v)});
  208. return;
  209. }else if(window.localStorage){
  210. value=window.localStorage.getItem(key);
  211. };
  212. cb(value);
  213. },
  214. };
  215. storage.getItem("keyConfig",v=>{
  216. if(v){
  217. var keys=v.split("");
  218. altKey=keys[0]!="0";
  219. ctrlKey=keys[1]!="0";
  220. shiftKey=keys[2]!="0";
  221. metaKey=keys[3]!="0";
  222. }
  223. if(/greasyfork\.org\/.*\/scripts\/24150[^\/]*$/.test(location.href)){
  224. var saveConfig=()=>{
  225. var conStr="";
  226. conStr+=altKey?"1":"0";
  227. conStr+=ctrlKey?"1":"0";
  228. conStr+=shiftKey?"1":"0";
  229. conStr+=metaKey?"1":"0";
  230. storage.setItem("keyConfig",conStr);
  231. };
  232. var keyEles=document.querySelectorAll("h1>em>code");
  233. keyEles[0].style.userSelect="none";
  234. keyEles[1].style.userSelect="none";
  235. keyEles[2].style.userSelect="none";
  236. keyEles[3].style.userSelect="none";
  237. keyEles[0].style.opacity=altKey?"":"0.3";
  238. keyEles[1].style.opacity=ctrlKey?"":"0.3";
  239. keyEles[2].style.opacity=shiftKey?"":"0.3";
  240. keyEles[3].style.opacity=metaKey?"":"0.3";
  241.  
  242. keyEles[0].onclick=e=>{
  243. altKey=!altKey;
  244. keyEles[0].style.opacity=altKey?"":"0.3";
  245. saveConfig();
  246. };
  247. keyEles[1].onclick=e=>{
  248. ctrlKey=!ctrlKey;
  249. keyEles[1].style.opacity=ctrlKey?"":"0.3";
  250. saveConfig();
  251. };
  252. keyEles[2].onclick=e=>{
  253. shiftKey=!shiftKey;
  254. keyEles[2].style.opacity=shiftKey?"":"0.3";
  255. saveConfig();
  256. };
  257. keyEles[3].onclick=e=>{
  258. metaKey=!metaKey;
  259. keyEles[3].style.opacity=metaKey?"":"0.3";
  260. saveConfig();
  261. };
  262. }
  263. });
  264.  
  265. _GM_registerMenuCommand("Custom input to highlight", ()=>{
  266. selStr=document.getSelection().toString();
  267. codes=selStr.replace(/&/g, "&amp;").replace(/\</g,"&lt;").replace(/\>/g,"&gt;");
  268. if(!codes){
  269. customInput=true;
  270. }
  271. highlight();
  272. });
  273. })();