HTML Sniffer

A tool to sniff HTML tags and attributes.

Verzia zo dňa 20.01.2016. Pozri najnovšiu verziu.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

// ==UserScript==
// @name HTML Sniffer
// @namespace http://gerald.top
// @author Gerald <[email protected]>
// @icon	http://cn.gravatar.com/avatar/a0ad718d86d21262ccd6ff271ece08a3?s=80
// @version 0.1.1
// @description A tool to sniff HTML tags and attributes.
// @include *
// @grant GM_addStyle
// @grant GM_getValue
// @grant GM_setValue
// ==/UserScript==

function prevent(e) {
  e.preventDefault();
}

function capture(e) {
  prevent(e);
  if (sniffer.current) {
    sniffer.current.classList.remove(sniffer.CURRENT);
  }
  sniffer.current = e.target;
  sniffer.current.classList.add(sniffer.CURRENT);
  updateDOM();
}

function onmouseover(e) {
  if (sniffer.hovered) {
    sniffer.hovered.classList.remove(sniffer.HOVERED);
  }
  sniffer.hovered = e.target;
  sniffer.hovered.classList.add(sniffer.HOVERED);
}

function safeHTML(html) {
  return html.replace(/[<&]/g, (m) => {
    return {
      '<' : '&lt;',
      '&' : '&amp;',
    }[m];
  });
}

function updateDOM() {
  var current = sniffer.current;
  var tagName = current.tagName.toLowerCase();
  var tags = document.querySelectorAll(tagName);
  var arrayProto = Array.prototype;
  var index = arrayProto.indexOf.call(tags, current);
  dom.domName.textContent = tagName;
  dom.domRank.textContent = `${index} of ${tags.length}`;
  dom.domAttrs.innerHTML = arrayProto.map.call(current.attributes, (attr) => {
    return `
    <li>
      <span class="dom-attr-key">${safeHTML(attr.name)}</span>
      =
      <span class="dom-attr-val">${safeHTML(attr.value)}</span>
    </li>
    `;
  }).join('');
}

function init() {
  initFrame();
  document.addEventListener('mousedown', capture, true);
  document.addEventListener('click', prevent, true);
  document.addEventListener('mouseover', onmouseover, false);
  locate(GM_getValue('hs-location'));
}

function locate(pos) {
  pos = pos || {};
  if (pos.left == null) pos.left = 'auto';
  else if (!isNaN(pos.left)) pos.left += 'px';
  if (pos.right == null) {
    pos.right = pos.left == 'auto' ? 0 : 'auto';
  } else if (!isNaN(pos.right)) pos.right += 'px';
  if (pos.bottom == null) pos.bottom = 'auto';
  else if (!isNaN(pos.bottom)) pos.bottom += 'px';
  if (pos.top == null) {
    pos.top = pos.bottom == 'auto' ? 0 : 'auto';
  } else if (!isNaN(pos.top)) pos.top += 'px';
  var frame = dom.frame;
  frame.style.top = pos.top;
  frame.style.left = pos.left;
  frame.style.right = pos.right;
  frame.style.bottom = pos.bottom;
}

function initFrame() {
  var frame = dom.frame = document.createElement('iframe');
  frame.id='hsniffer';
  document.body.appendChild(frame);
  var doc = frame.contentDocument;
  var style = doc.createElement('style');
  style.innerHTML = `
    body {
      min-height: 100%;
      padding: 1em;
      background: wheat;
      cursor: move;
    }
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    .dom {
      cursor: text;
    }
    ul {
      padding: 20px;
    }
    .dom-attr-key {
      color: dodgerblue;
    }
    .dom-attr-val {
      color: green;
    }
  `;
  doc.head.appendChild(style);
  doc.body.innerHTML = `
  <h1>HTML Sniffer</h1>
  <div class="dom">
  Current DOM: <span class="dom-name"></span>
  <br>
  Rank: <span class="dom-rank"></span>
  <br><ul class="dom-attrs"></ul>
  </div>
  `;
  dom.dom = doc.body.querySelector('.dom');
  dom.domName = doc.body.querySelector('.dom-name');
  dom.domRank = doc.body.querySelector('.dom-rank');
  dom.domAttrs = doc.body.querySelector('.dom-attrs');
  doc.addEventListener('mousedown', onMoveStart, false);

  var moving;
  function onMoveStart(e) {
    if (dom.dom.contains(e.target)) return;
    e.preventDefault();
    if (moving) return;
    moving = {
      x: e.clientX,
      y: e.clientY,
    };
    doc.addEventListener('mousemove', onMoving, false);
    doc.addEventListener('mouseup', onMoveEnd, false);
  }
  function onMoving(e) {
    var rect = frame.getBoundingClientRect();
    locate({
      left: rect.left + e.clientX - moving.x,
      top: rect.top + e.clientY - moving.y,
    });
  }
  function onMoveEnd(e) {
    var rect = frame.getBoundingClientRect();
    var pos = {};
    var right = document.body.clientWidth - rect.right;
    if (rect.left > right) pos.right = right;
    else pos.left = rect.left;
    var bottom = document.body.clientHeight - rect.bottom;
    if (rect.top > bottom) pos.bottom = bottom;
    else pos.top = rect.top;
    locate(pos);
    GM_setValue('hs-location', pos);
    moving = null;
    doc.removeEventListener('mousemove', onMoving, false);
    doc.removeEventListener('mouseup', onMoveEnd, false);
  }
}

GM_addStyle(`
  #hsniffer {
    position: fixed;
    width: 300px;
    height: 300px;
    border: 2px ridge gray;
    z-index: 10000;
  }
  *:not(#hsniffer).hsniffer-highlight {
    background: rgba(0,128,255,.3) !important;
    outline: 2px solid orange !important;
  }
  .hsniffer-current {
    background: rgba(0,128,255,.5) !important;
    outline: 2px solid red !important;
  }
`);
var dom = {};
var sniffer = {
  HOVERED: 'hsniffer-highlight',
  CURRENT: 'hsniffer-current',
};
init();