shwifty659 / VkAwayLinksFix

// ==UserScript==
// @namespace     https://openuserjs.org/users/shwifty659
// @name          VkAwayLinksFix
// @description   Changes vk.com links from 'https://vk.com/away.php?to=<url>...' to <url>. (vk.com requires sign in when you click these links)
// @license       MIT
// @version       1.0.0
// @include       https://vk.com/*
// @grant         none
// @run-at        document-end
// ==/UserScript==

// ==OpenUserJS==
// @author shwifty659
// ==/OpenUserJS==

(function () {
  'use strict';

  const hrefPrefix = 'https://vk.com/away.php?';

  // fix links initially
  fixNestedLinks(document.body);

  // fix links on DOM updates
  const observer = new MutationObserver(mutationCallback);
  observer.observe(document.body, {
    attributes: true,
    childList: true,
    subtree: true
  });

  // Fix '<a href="...">' element: change href value from 'https://vk.com/away.php?to=<url>...' to <url>
  function fixVkAwayLinkElem(linkElem) {
    const href = linkElem.href;
    if (!(href && href.startsWith(hrefPrefix))) {
      return;
    }
    const urlParams = new URLSearchParams(href.substring(hrefPrefix.length));
    if (urlParams.has('to')) {
      linkElem.href = urlParams.get('to');
    }
  }

  // Fix nested link elements
  function fixNestedLinks(rootNode) {
    if (!(rootNode && rootNode.querySelectorAll)) {
      return;
    }
    const linkElems = rootNode.querySelectorAll('a[href^="/away.php?"]');
    linkElems.forEach((linkElem) => fixVkAwayLinkElem(linkElem));
  }

  // Callback function to execute when mutations are observed
  function mutationCallback(mutationsList) {
    for (const mutation of mutationsList) {
      switch (mutation.type) {
        case 'childList':
          /* One or more children have been added to and/or removed from the tree. (See mutation.addedNodes and mutation.removedNodes.) */
          mutation.addedNodes.forEach((addedNode) => fixNestedLinks(addedNode));
          break;
        case 'attributes':
          /* An attribute value changed on the element in mutation.target. The attribute name is in mutation.attributeName, and its previous value is in mutation.oldValue. */
          if (mutation.attribute === 'href') {
            fixVkAwayLinkElem(mutation.target);
          }
          break;
      }
    }
  }
})();