HTML Sniffer

A tool to sniff HTML tags and attributes.

目前为 2016-01-20 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name HTML Sniffer
  3. // @namespace http://gerald.top
  4. // @author Gerald <i@gerald.top>
  5. // @icon http://cn.gravatar.com/avatar/a0ad718d86d21262ccd6ff271ece08a3?s=80
  6. // @version 0.1.1
  7. // @description A tool to sniff HTML tags and attributes.
  8. // @include *
  9. // @grant GM_addStyle
  10. // @grant GM_getValue
  11. // @grant GM_setValue
  12. // ==/UserScript==
  13.  
  14. function prevent(e) {
  15. e.preventDefault();
  16. }
  17.  
  18. function capture(e) {
  19. prevent(e);
  20. if (sniffer.current) {
  21. sniffer.current.classList.remove(sniffer.CURRENT);
  22. }
  23. sniffer.current = e.target;
  24. sniffer.current.classList.add(sniffer.CURRENT);
  25. updateDOM();
  26. }
  27.  
  28. function onmouseover(e) {
  29. if (sniffer.hovered) {
  30. sniffer.hovered.classList.remove(sniffer.HOVERED);
  31. }
  32. sniffer.hovered = e.target;
  33. sniffer.hovered.classList.add(sniffer.HOVERED);
  34. }
  35.  
  36. function safeHTML(html) {
  37. return html.replace(/[<&]/g, (m) => {
  38. return {
  39. '<' : '&lt;',
  40. '&' : '&amp;',
  41. }[m];
  42. });
  43. }
  44.  
  45. function updateDOM() {
  46. var current = sniffer.current;
  47. var tagName = current.tagName.toLowerCase();
  48. var tags = document.querySelectorAll(tagName);
  49. var arrayProto = Array.prototype;
  50. var index = arrayProto.indexOf.call(tags, current);
  51. dom.domName.textContent = tagName;
  52. dom.domRank.textContent = `${index} of ${tags.length}`;
  53. dom.domAttrs.innerHTML = arrayProto.map.call(current.attributes, (attr) => {
  54. return `
  55. <li>
  56. <span class="dom-attr-key">${safeHTML(attr.name)}</span>
  57. =
  58. <span class="dom-attr-val">${safeHTML(attr.value)}</span>
  59. </li>
  60. `;
  61. }).join('');
  62. }
  63.  
  64. function init() {
  65. initFrame();
  66. document.addEventListener('mousedown', capture, true);
  67. document.addEventListener('click', prevent, true);
  68. document.addEventListener('mouseover', onmouseover, false);
  69. locate(GM_getValue('hs-location'));
  70. }
  71.  
  72. function locate(pos) {
  73. pos = pos || {};
  74. if (pos.left == null) pos.left = 'auto';
  75. else if (!isNaN(pos.left)) pos.left += 'px';
  76. if (pos.right == null) {
  77. pos.right = pos.left == 'auto' ? 0 : 'auto';
  78. } else if (!isNaN(pos.right)) pos.right += 'px';
  79. if (pos.bottom == null) pos.bottom = 'auto';
  80. else if (!isNaN(pos.bottom)) pos.bottom += 'px';
  81. if (pos.top == null) {
  82. pos.top = pos.bottom == 'auto' ? 0 : 'auto';
  83. } else if (!isNaN(pos.top)) pos.top += 'px';
  84. var frame = dom.frame;
  85. frame.style.top = pos.top;
  86. frame.style.left = pos.left;
  87. frame.style.right = pos.right;
  88. frame.style.bottom = pos.bottom;
  89. }
  90.  
  91. function initFrame() {
  92. var frame = dom.frame = document.createElement('iframe');
  93. frame.id='hsniffer';
  94. document.body.appendChild(frame);
  95. var doc = frame.contentDocument;
  96. var style = doc.createElement('style');
  97. style.innerHTML = `
  98. body {
  99. min-height: 100%;
  100. padding: 1em;
  101. background: wheat;
  102. cursor: move;
  103. }
  104. * {
  105. margin: 0;
  106. padding: 0;
  107. box-sizing: border-box;
  108. }
  109. .dom {
  110. cursor: text;
  111. }
  112. ul {
  113. padding: 20px;
  114. }
  115. .dom-attr-key {
  116. color: dodgerblue;
  117. }
  118. .dom-attr-val {
  119. color: green;
  120. }
  121. `;
  122. doc.head.appendChild(style);
  123. doc.body.innerHTML = `
  124. <h1>HTML Sniffer</h1>
  125. <div class="dom">
  126. Current DOM: <span class="dom-name"></span>
  127. <br>
  128. Rank: <span class="dom-rank"></span>
  129. <br><ul class="dom-attrs"></ul>
  130. </div>
  131. `;
  132. dom.dom = doc.body.querySelector('.dom');
  133. dom.domName = doc.body.querySelector('.dom-name');
  134. dom.domRank = doc.body.querySelector('.dom-rank');
  135. dom.domAttrs = doc.body.querySelector('.dom-attrs');
  136. doc.addEventListener('mousedown', onMoveStart, false);
  137.  
  138. var moving;
  139. function onMoveStart(e) {
  140. if (dom.dom.contains(e.target)) return;
  141. e.preventDefault();
  142. if (moving) return;
  143. moving = {
  144. x: e.clientX,
  145. y: e.clientY,
  146. };
  147. doc.addEventListener('mousemove', onMoving, false);
  148. doc.addEventListener('mouseup', onMoveEnd, false);
  149. }
  150. function onMoving(e) {
  151. var rect = frame.getBoundingClientRect();
  152. locate({
  153. left: rect.left + e.clientX - moving.x,
  154. top: rect.top + e.clientY - moving.y,
  155. });
  156. }
  157. function onMoveEnd(e) {
  158. var rect = frame.getBoundingClientRect();
  159. var pos = {};
  160. var right = document.body.clientWidth - rect.right;
  161. if (rect.left > right) pos.right = right;
  162. else pos.left = rect.left;
  163. var bottom = document.body.clientHeight - rect.bottom;
  164. if (rect.top > bottom) pos.bottom = bottom;
  165. else pos.top = rect.top;
  166. locate(pos);
  167. GM_setValue('hs-location', pos);
  168. moving = null;
  169. doc.removeEventListener('mousemove', onMoving, false);
  170. doc.removeEventListener('mouseup', onMoveEnd, false);
  171. }
  172. }
  173.  
  174. GM_addStyle(`
  175. #hsniffer {
  176. position: fixed;
  177. width: 300px;
  178. height: 300px;
  179. border: 2px ridge gray;
  180. z-index: 10000;
  181. }
  182. *:not(#hsniffer).hsniffer-highlight {
  183. background: rgba(0,128,255,.3) !important;
  184. outline: 2px solid orange !important;
  185. }
  186. .hsniffer-current {
  187. background: rgba(0,128,255,.5) !important;
  188. outline: 2px solid red !important;
  189. }
  190. `);
  191. var dom = {};
  192. var sniffer = {
  193. HOVERED: 'hsniffer-highlight',
  194. CURRENT: 'hsniffer-current',
  195. };
  196. init();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址