viewsource

View and beautify page source. Shortcut: Alt+U.

As of 2018-05-19. See the latest version.

  1. // ==UserScript==
  2. // @name viewsource
  3. // @namespace devs.forumvi.com
  4. // @description View and beautify page source. Shortcut: Alt+U.
  5. // @version 3.1.0
  6. // @icon http://i.imgur.com/6yZMOeH.png
  7. // @author Zzbaivong
  8. // @oujs:author baivong
  9. // @license MIT; https://baivong.mit-license.org/license.txt
  10. // @match http://*/*
  11. // @match https://*/*
  12. // @resource js_beautify https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.7.5/beautify.min.js
  13. // @resource css_beautify https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.7.5/beautify-css.min.js
  14. // @resource html_beautify https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.7.5/beautify-html.min.js
  15. // @resource hljs https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js
  16. // @require https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js?v=a834d46
  17. // @noframes
  18. // @connect *
  19. // @supportURL https://github.com/lelinhtinh/Userscript/issues
  20. // @run-at document-idle
  21. // @grant GM.getResourceUrl
  22. // @grant GM_getResourceURL
  23. // @grant GM.xmlHttpRequest
  24. // @grant GM_xmlhttpRequest
  25. // @grant GM.openInTab
  26. // @grant GM_openInTab
  27. // @grant GM_registerMenuCommand
  28. // ==/UserScript==
  29.  
  30. /* eslint-env worker, es6 */
  31. (function () {
  32. 'use strict';
  33.  
  34. var doc = document,
  35. urlpage = location.href,
  36. urlbeautify = 'https://lelinhtinh.github.io/Userscript/?beautify-source=';
  37.  
  38. if (!/^application\/(xhtml+xml|xml|rss+xml)|text\/(html|xml)$/.test(doc.contentType)) return;
  39.  
  40. if (urlpage.indexOf(urlbeautify) !== 0) {
  41. var viewsource = function () {
  42. if (urlpage.indexOf(urlbeautify) === 0) return;
  43. GM.openInTab(urlbeautify + encodeURIComponent(urlpage), false);
  44. };
  45.  
  46. GM_registerMenuCommand('Beautify Page Source', viewsource, 'u');
  47. doc.onkeydown = function (e) {
  48. if (e.which === 85 && e.altKey) { // Alt+U
  49. e.preventDefault();
  50. viewsource();
  51. }
  52. };
  53.  
  54. return;
  55. }
  56.  
  57. urlbeautify = urlpage.replace(urlbeautify, '');
  58. urlbeautify = decodeURIComponent(urlbeautify);
  59.  
  60. var blobURL, worker,
  61.  
  62. addstyle = function (aCss) {
  63. var head = doc.getElementsByTagName('head')[0];
  64. if (!head) return null;
  65. var style = doc.createElement('style');
  66. style.setAttribute('type', 'text/css');
  67. style.textContent = aCss;
  68. head.appendChild(style);
  69. return style;
  70. };
  71.  
  72. blobURL = URL.createObjectURL(new Blob(['(',
  73. function () {
  74. self.window = {};
  75.  
  76. self.onmessage = function (e) {
  77. var source = e.data.content;
  78.  
  79. importScripts(e.data.libs[0]);
  80. importScripts(e.data.libs[1]);
  81. importScripts(e.data.libs[2]);
  82. source = self.window.html_beautify(source, { indent_scripts: 'keep' });
  83.  
  84. self.postMessage({
  85. action: 'beautify',
  86. source: source
  87. });
  88.  
  89. importScripts(e.data.libs[3]);
  90. source = self.window.hljs.highlight('xml', source, true).value;
  91.  
  92. source = source.split('\n');
  93. source = source.join('</code><code>');
  94. source = '<code>' + source + '</code>';
  95.  
  96. self.postMessage({
  97. action: 'hljs',
  98. source: source
  99. });
  100. };
  101.  
  102. }.toString(),
  103. ')()'
  104. ], {
  105. type: 'text/javascript'
  106. }));
  107. worker = new Worker(blobURL);
  108.  
  109. worker.onmessage = function (e) {
  110. if (!e.data) return;
  111. var fragment = doc.createDocumentFragment(),
  112. pre = doc.createElement('pre');
  113.  
  114. if (e.data.action === 'beautify') {
  115. addstyle('*{margin:0;padding:0}html{line-height:1em;background:#1d1f21;color:#c5c8c6}pre{counter-reset:line-numbers;white-space:pre-wrap;word-wrap:break-word;word-break:break-all}code::before{counter-increment:line-numbers;content:counter(line-numbers);display:block;position:absolute;left:-4.5em;top:0;width:4em;text-align:right;color:#60686f;white-space:pre}code{display:block;position:relative;margin-left:4em;padding-left:.5em;min-height:1em;border-left:1px solid #32363b}pre{padding:.5em .5em .5em 5em;border-left:1px solid #1d1f21}pre.hljs{padding-left:.5em;border-left:0 none}code::after{content:".";visibility:hidden}a{color:#b5bd68}a:active,a:hover,a:visited{color:#8b9433} .hljs-comment,.hljs-quote{color:#969896}.hljs-variable,.hljs-template-variable,.hljs-tag,.hljs-name,.hljs-selector-id,.hljs-selector-class,.hljs-regexp,.hljs-deletion{color:#c66}.hljs-number,.hljs-built_in,.hljs-builtin-name,.hljs-literal,.hljs-type,.hljs-params,.hljs-meta,.hljs-link{color:#de935f}.hljs-attribute{color:#f0c674}.hljs-string,.hljs-symbol,.hljs-bullet,.hljs-addition{color:#b5bd68}.hljs-title,.hljs-section{color:#81a2be}.hljs-keyword,.hljs-selector-tag{color:#b294bb}.hljs{display:block;overflow-x:auto;background:#1d1f21;color:#c5c8c6;padding:.5em}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}');
  116.  
  117. pre.textContent = e.data.source;
  118. fragment.appendChild(pre);
  119. doc.body.appendChild(fragment);
  120. } else {
  121. pre.innerHTML = e.data.source;
  122. pre.className = 'hljs xml';
  123. fragment.appendChild(pre);
  124. doc.body.replaceChild(fragment, doc.getElementsByTagName('pre')[0]);
  125.  
  126. var attrUrl = doc.getElementsByClassName('hljs-attr');
  127. for (var j = 0; j < attrUrl.length; j++) {
  128. if (/\b(src|href\b)/.test(attrUrl[j].textContent)) {
  129. var link = attrUrl[j].nextSibling.nextSibling,
  130. url = link.textContent,
  131. quote = url.slice(0, 1);
  132.  
  133. if (quote !== '\'' && quote !== '"') {
  134. quote = '';
  135. } else {
  136. url = url.slice(1, -1);
  137. }
  138.  
  139. link.innerHTML = quote + '<a href="' + url + '" target="_blank">' + url + '</a>' + quote;
  140. }
  141. }
  142. }
  143. };
  144.  
  145. var js_beautify = GM.getResourceUrl('js_beautify'),
  146. css_beautify = GM.getResourceUrl('css_beautify'),
  147. html_beautify = GM.getResourceUrl('html_beautify'),
  148. hljs = GM.getResourceUrl('hljs');
  149.  
  150. GM.xmlHttpRequest({
  151. method: 'GET',
  152. url: urlbeautify,
  153. onload: function (response) {
  154. doc.title = 'beautify-source:' + urlbeautify;
  155.  
  156. Promise.all([js_beautify, css_beautify, html_beautify, hljs]).then(function (urls) {
  157. worker.postMessage({
  158. libs: urls,
  159. content: response.response
  160. });
  161. });
  162.  
  163. var baseUrl,
  164. baseMatch = response.response.match(/<base\s+href="([^"]+)"\s?[^>]*>/),
  165. base = doc.createElement('base');
  166.  
  167. baseUrl = baseMatch ? baseMatch[1] : urlbeautify.replace(/[^/]*$/, '');
  168.  
  169. base.href = baseUrl;
  170. doc.head.appendChild(base);
  171. }
  172. });
  173.  
  174. }());