Clickable domain in Google search results

Ever wanted to get at the main page of the sought-for website right from the Google search results? Now you can

Ekde 2021/03/14. Vidu La ĝisdata versio.

// ==UserScript==
// @name            Clickable domain in Google search results
// @description     Ever wanted to get at the main page of the sought-for website right from the Google search results? Now you can
//
// @name:ru         Кликабельный домен в результатах поиска Google
// @description:ru  Иногда хочется перейти на главную страницу искомого сайта прямо из результатов поиска Google? Теперь можно
//
// @version         1.0.0
// @author          Konf
// @namespace       https://greasyfork.org/users/424058
// @compatible      Chrome
// @compatible      Opera
// @compatible      Firefox
// @icon            https://s2.googleusercontent.com/s2/favicons?domain=google.com&sz=32
// @match           https://google.com
// @include         /^http(s|):\/\/(www\.|)google.(com|net|de|ru|co\.uk)\/search\?.*$/
// @run-at          document-end
// @grant           none
// @noframes
// ==/UserScript==

/* jshint esversion: 6 */

(function() {
  'use strict';

  const divider = '›';
  const targetTagName = 'cite';
  const duplicatedTargets = document.body.querySelectorAll(targetTagName);
  const duplicatedTargetsArr = Array.prototype.slice.call(duplicatedTargets);

  const targetClasses = (function() {
    const measureObj = {};
    const biggest = { className: '', count: 0 };

    duplicatedTargetsArr.forEach((el, id) => {
      const number = measureObj[el.className] || 0;
      measureObj[el.className] = number + 1;
    });

    for (const className in measureObj) {
      const count = measureObj[className];

      if (count === biggest.count) throwError();

      if (count > biggest.count) {
        biggest.count = count;
        biggest.className = className;
      }
    }

    if (!biggest.className) throwError();

    return biggest.className;
  }());

  const filteredTargets = duplicatedTargetsArr.filter(el => { return el.className === targetClasses });

  if (filteredTargets.length % 2 !== 0) throwError();

  const sortedTargets = {
    type1: [],
    type2: []
  }

  filteredTargets.forEach((el, id) => {
    if (id % 2 === 0) {
      sortedTargets.type1.push(el);
    } else {
      sortedTargets.type2.push({ caption: el });
    }
  });

  (function() {
    const keyParentNode = sortedTargets.type2[0].caption.parentNode.parentNode;

    if (findComputedStyle(keyParentNode, 'visibility') !== 'hidden') throwError();
  }());

  sortedTargets.type1.forEach((el, id) => {
    const link = findNodeFromChild(el, 'a[ping]', 3);

    if (!link) return;

    el.style.display = 'none';
    sortedTargets.type2[id].link = link;
  });

  sortedTargets.type2.forEach((el) => {
    el.caption.parentNode.parentNode.style.visibility = 'visible';
  });

  for (const obj of sortedTargets.type2) {
    if (!obj.link) continue;

    const url = new URL(obj.link.href);
    const captionHost = obj.caption.innerText.split(divider)[0].trim();
    const newLink = `
      <a href="${url.protocol + '//' + captionHost}">${captionHost}</a>
    `;

    obj.caption.innerHTML = obj.caption.innerHTML.replace(captionHost, newLink);
  }


  // utils -------------------------------------------------------------------

  function findComputedStyle(el, styleProp) {
    function camelize(str) {
      return str.replace(/-(\w)/g, function(str, letter){
        return letter.toUpperCase();
      });
    }

    if (el.currentStyle) {
      return el.currentStyle[camelize(styleProp)];
    } else if (document.defaultView && document.defaultView.getComputedStyle) {
      return document.defaultView.getComputedStyle(el, null)
                                 .getPropertyValue(styleProp);
    } else {
      return el.style[camelize(styleProp)];
    }
  }

  function findNodeFromChild(child, query, depth) {
    let testNode = child.parentNode;
    let counter = 1;

    while (testNode && depth !== counter++) {
      if (testNode.matches(query)) return testNode;
      testNode = testNode.parentNode;
    }
  }

  function throwError() {
    throw new Error('Google breadcrumbs script error: Google has changed pages layout');
  }

  // -------------------------------------------------------------------------
})();