Spacing.js

A JavaScript utility for measuring the spacing between elements on webpage.

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

// ==UserScript==
// @name         Spacing.js
// @namespace    https://github.com/stevenlei
// @version      1.0.5
// @description  A JavaScript utility for measuring the spacing between elements on webpage.
// @author       Steven Lei <[email protected]>
// @run-at       document-start
// @include      *
// @license      MIT
// ==/UserScript==
'use strict';
/*!
 * Spacing.js v1.0.5
 * Copyright (c) 2021 Steven Lei
 * Released under the MIT License.
*/
/******/ (() => { // webpackBootstrap
/******/ 	"use strict";
/******/ 	// The require scope
/******/ 	var __webpack_require__ = {};
/******/ 	
/************************************************************************/
/******/ 	/* webpack/runtime/make namespace object */
/******/ 	(() => {
/******/ 		// define __esModule on exports
/******/ 		__webpack_require__.r = (exports) => {
/******/ 			if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ 				Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ 			}
/******/ 			Object.defineProperty(exports, '__esModule', { value: true });
/******/ 		};
/******/ 	})();
/******/ 	
/************************************************************************/
var __webpack_exports__ = {};
// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);

;// CONCATENATED MODULE: ./src/rect.ts
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

var Rect = /*#__PURE__*/function () {
  function Rect(rect) {
    _classCallCheck(this, Rect);

    this.top = rect.top;
    this.left = rect.left;
    this.width = rect.width;
    this.height = rect.height;
    this.right = rect.right;
    this.bottom = rect.bottom;
  }

  _createClass(Rect, [{
    key: "colliding",
    value: function colliding(other) {
      return !(this.top > other.bottom || this.right < other.left || this.bottom < other.top || this.left > other.right);
    }
  }, {
    key: "containing",
    value: function containing(other) {
      return this.left <= other.left && other.left < this.width && this.top <= other.top && other.top < this.height;
    }
  }, {
    key: "inside",
    value: function inside(other) {
      return other.top <= this.top && this.top <= other.bottom && other.top <= this.bottom && this.bottom <= other.bottom && other.left <= this.left && this.left <= other.right && other.left <= this.right && this.right <= other.right;
    }
  }]);

  return Rect;
}();


;// CONCATENATED MODULE: ./src/placeholder.ts
function createPlaceholderElement(type, width, height, top, left, color) {
  var placeholder = document.createElement('div');
  placeholder.classList.add("spacing-js-".concat(type, "-placeholder"));
  placeholder.style.border = "2px solid ".concat(color);
  placeholder.style.position = 'fixed';
  placeholder.style.background = 'none';
  placeholder.style.borderRadius = '2px';
  placeholder.style.padding = '0';
  placeholder.style.margin = '0';
  placeholder.style.width = "".concat(width - 2, "px");
  placeholder.style.height = "".concat(height - 2, "px");
  placeholder.style.top = "".concat(top - 1, "px");
  placeholder.style.left = "".concat(left - 1, "px");
  placeholder.style.pointerEvents = 'none';
  placeholder.style.zIndex = '9999';
  placeholder.style.boxSizing = 'content-box';
  document.body.appendChild(placeholder);
}
function clearPlaceholderElement(type) {
  var _document$querySelect;

  (_document$querySelect = document.querySelector(".spacing-js-".concat(type, "-placeholder"))) === null || _document$querySelect === void 0 ? void 0 : _document$querySelect.remove();
}
;// CONCATENATED MODULE: ./src/marker.ts
function createLine(width, height, top, left, text) {
  var border = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 'none';
  var marker = document.createElement('span');
  marker.style.backgroundColor = 'red';
  marker.style.position = 'fixed';
  marker.classList.add("spacing-js-marker");
  marker.style.width = "".concat(width, "px");
  marker.style.height = "".concat(height, "px");

  if (border === 'x') {
    marker.style.borderLeft = '1px solid rgba(255, 255, 255, .8)';
    marker.style.borderRight = '1px solid rgba(255, 255, 255, .8)';
  }

  if (border === 'y') {
    marker.style.borderTop = '1px solid rgba(255, 255, 255, .8)';
    marker.style.borderBottom = '1px solid rgba(255, 255, 255, .8)';
  }

  marker.style.pointerEvents = 'none';
  marker.style.top = "".concat(top, "px");
  marker.style.left = "".concat(left, "px");
  marker.style.zIndex = '9998';
  marker.style.boxSizing = 'content-box';
  var value = document.createElement('span');
  value.classList.add("spacing-js-value");
  value.style.backgroundColor = 'red';
  value.style.color = 'white';
  value.style.fontSize = '10px';
  value.style.display = 'inline-block';
  value.style.fontFamily = 'Helvetica, sans-serif';
  value.style.fontWeight = 'bold';
  value.style.borderRadius = '20px';
  value.style.position = 'fixed';
  value.style.width = '42px';
  value.style.lineHeight = '15px';
  value.style.height = '16px';
  value.style.textAlign = 'center';
  value.style.zIndex = '10000';
  value.style.pointerEvents = 'none';
  value.innerText = text;
  value.style.boxSizing = 'content-box';

  if (border === 'x') {
    // Prevent the badge moved outside the screen
    var topOffset = top + height / 2 - 7;

    if (topOffset > document.documentElement.clientHeight - 20) {
      topOffset = document.documentElement.clientHeight - 20;
    }

    if (topOffset < 0) {
      topOffset = 6;
    }

    value.style.top = "".concat(topOffset, "px");
    value.style.left = "".concat(left + 6, "px");
  } else if (border === 'y') {
    // Prevent the badge moved outside the screen
    var leftOffset = left + width / 2 - 20;

    if (leftOffset > document.documentElement.clientWidth - 48) {
      leftOffset = document.documentElement.clientWidth - 48;
    }

    if (leftOffset < 0) {
      leftOffset = 6;
    }

    value.style.top = "".concat(top + 6, "px");
    value.style.left = "".concat(leftOffset, "px");
  }

  document.body.appendChild(marker);
  document.body.appendChild(value);
}

function placeMark(rect1, rect2, direction, value) {
  var edgeToEdge = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;

  if (direction === 'top') {
    var width = 1;
    var height = Math.abs(rect1.top - rect2.top);
    var left = Math.floor((Math.min(rect1.right, rect2.right) + Math.max(rect1.left, rect2.left)) / 2);
    var top = Math.min(rect1.top, rect2.top);

    if (edgeToEdge) {
      if (rect1.top < rect2.top) {
        return;
      } // If not colliding


      if (rect1.right < rect2.left || rect1.left > rect2.right) {
        return;
      }

      height = Math.abs(rect2.bottom - rect1.top);
      top = Math.min(rect2.bottom, rect1.top);
    }

    createLine(width, height, top, left, value, 'x');
  } else if (direction === 'left') {
    var _width = Math.abs(rect1.left - rect2.left);

    var _height = 1;

    var _top = Math.floor((Math.min(rect1.bottom, rect2.bottom) + Math.max(rect1.top, rect2.top)) / 2);

    var _left = Math.min(rect1.left, rect2.left);

    if (edgeToEdge) {
      if (rect1.left < rect2.left) {
        return;
      } // If not overlapping


      if (rect1.bottom < rect2.top || rect1.top > rect2.bottom) {
        return;
      }

      _width = Math.abs(rect1.left - rect2.right);
      _left = Math.min(rect2.right, rect1.left);
    }

    createLine(_width, _height, _top, _left, value, 'y');
  } else if (direction === 'right') {
    var _width2 = Math.abs(rect1.right - rect2.right);

    var _height2 = 1;

    var _top2 = Math.floor((Math.min(rect1.bottom, rect2.bottom) + Math.max(rect1.top, rect2.top)) / 2);

    var _left2 = Math.min(rect1.right, rect2.right);

    if (edgeToEdge) {
      if (rect1.left > rect2.right) {
        return;
      } // If not overlapping


      if (rect1.bottom < rect2.top || rect1.top > rect2.bottom) {
        return;
      }

      _width2 = Math.abs(rect1.right - rect2.left);
    }

    createLine(_width2, _height2, _top2, _left2, value, 'y');
  } else if (direction === 'bottom') {
    var _width3 = 1;

    var _height3 = Math.abs(rect1.bottom - rect2.bottom);

    var _top3 = Math.min(rect1.bottom, rect2.bottom);

    var _left3 = Math.floor((Math.min(rect1.right, rect2.right) + Math.max(rect1.left, rect2.left)) / 2);

    if (edgeToEdge) {
      if (rect2.bottom < rect1.top) {
        return;
      } // If not overlapping


      if (rect1.right < rect2.left || rect1.left > rect2.right) {
        return;
      }

      _height3 = Math.abs(rect1.bottom - rect2.top);
    }

    createLine(_width3, _height3, _top3, _left3, value, 'x');
  }
}
function removeMarks() {
  document.querySelectorAll('.spacing-js-marker').forEach(function (element) {
    element.remove();
  });
  document.querySelectorAll('.spacing-js-value').forEach(function (element) {
    element.remove();
  });
}
;// CONCATENATED MODULE: ./src/spacing.ts



var active = false;
var selectedElement;
var targetElement;
var originalBodyOverflow;
var Spacing = {
  start: function start() {
    if (!document.body) {
      console.warn("Unable to initialise, document.body does not exist.");
      return;
    }

    window.addEventListener('keydown', function (e) {
      if (e.key === 'Alt' && !active) {
        e.preventDefault();
        active = true;
        setSelectedElement();
        preventPageScroll(true);
      }
    });
    window.addEventListener('keyup', function (e) {
      active = false;
      clearPlaceholderElement('selected');
      clearPlaceholderElement('target');
      selectedElement = null;
      targetElement = null;
      removeMarks();
      preventPageScroll(false);
    });
    window.addEventListener('mousemove', function (e) {
      setTargetElement().then(function () {
        if (selectedElement != null && targetElement != null) {
          // Do the calculation
          var selectedElementRect = selectedElement.getBoundingClientRect();
          var targetElementRect = targetElement.getBoundingClientRect();
          var selected = new Rect(selectedElementRect);
          var target = new Rect(targetElementRect);
          removeMarks();
          var top, bottom, left, right, outside;

          if (selected.containing(target) || selected.inside(target) || selected.colliding(target)) {
            console.log("containing || inside || colliding");
            top = Math.round(Math.abs(selectedElementRect.top - targetElementRect.top));
            bottom = Math.round(Math.abs(selectedElementRect.bottom - targetElementRect.bottom));
            left = Math.round(Math.abs(selectedElementRect.left - targetElementRect.left));
            right = Math.round(Math.abs(selectedElementRect.right - targetElementRect.right));
            outside = false;
          } else {
            console.log("outside");
            top = Math.round(Math.abs(selectedElementRect.top - targetElementRect.bottom));
            bottom = Math.round(Math.abs(selectedElementRect.bottom - targetElementRect.top));
            left = Math.round(Math.abs(selectedElementRect.left - targetElementRect.right));
            right = Math.round(Math.abs(selectedElementRect.right - targetElementRect.left));
            outside = true;
          }

          placeMark(selected, target, 'top', "".concat(top, "px"), outside);
          placeMark(selected, target, 'bottom', "".concat(bottom, "px"), outside);
          placeMark(selected, target, 'left', "".concat(left, "px"), outside);
          placeMark(selected, target, 'right', "".concat(right, "px"), outside);
        }
      });
    });
  }
};

function setSelectedElement() {
  var elements = document.querySelectorAll(':hover');
  var el = elements[elements.length - 1];

  if (el !== selectedElement) {
    selectedElement = el;
    clearPlaceholderElement('selected');
    var rect = selectedElement.getBoundingClientRect();
    createPlaceholderElement('selected', rect.width, rect.height, rect.top, rect.left, "red");
  }
}

function setTargetElement() {
  return new Promise(function (resolve, reject) {
    var elements = document.querySelectorAll(':hover');
    var el = elements[elements.length - 1];

    if (active && el !== selectedElement && el !== targetElement) {
      targetElement = el;
      clearPlaceholderElement('target');
      var rect = targetElement.getBoundingClientRect();
      createPlaceholderElement('target', rect.width, rect.height, rect.top, rect.left, 'blue');
      resolve();
    }
  });
}

function preventPageScroll(active) {
  if (active) {
    window.addEventListener('DOMMouseScroll', scrollingPreventDefault, false);
    window.addEventListener('wheel', scrollingPreventDefault, {
      passive: false
    });
    window.addEventListener('mousewheel', scrollingPreventDefault, {
      passive: false
    });
  } else {
    window.removeEventListener('DOMMouseScroll', scrollingPreventDefault);
    window.removeEventListener('wheel', scrollingPreventDefault);
    window.removeEventListener('mousewheel', scrollingPreventDefault);
  }
}

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

/* harmony default export */ const spacing = (Spacing);
;// CONCATENATED MODULE: ./src/index.ts
 // Simple, Start.

spacing.start();
window.Spacing = __webpack_exports__;
/******/ })()
;