Search code examples
javascriptgoogle-chrome-extensionuserscripts

Wrong href of dynamically created "a" (anchor) element on archive.org site


I use this code to create "a" element to add it to the page. (On 3rd party site, it's a userscript)

let anchor = document.createElement("a");
anchor.href = new URL("https://duckduckgo.com");
console.log(anchor);

//anchor.target = "_blank";
//anchor.rel = "nofollow noopener noreferrer";
//anchor.click();

Run this code in the console to check it.

This code works OK on all sites, except some pages on web.archive.org

For example:

on https://web.archive.org/web/19961220154510/https://www.yahoo.com/

I get <a href="https://web.archive.org/web/19961220154510if_/https://duckduckgo.com/"></a>,

but should <a href="https://duckduckgo.com/"></a>.

.click() (on it) opens this wrong URL.

How to fix it?

It happens in both Chrome and Firefox.


UPD: window.open("https://duckduckgo.com") works wrong too.

It opens https://web.archive.org/web/20080820060021/http://duckduckgo.com/ instead https://duckduckgo.com/.


Solution

  • This is occurring because Javascript on that site is overwriting HTMLAnchorElement.prototype.href:

    enter image description here

    Overwriting native prototypes is bad practice and results in confusing errors like these.

    For a userscript, you can fix it by saving a reference to the href property descriptor at the beginning of pageload, then reassign it to HTMLAnchorElement.prototype.href after the bad built-in code has tried to reassign it:

    // ==UserScript==
    // @name             0 New Userscript
    // @include          https://web.archive.org/web/19961220154510/https://www.yahoo.com/
    // @run-at           document-start
    // @grant            none
    // ==/UserScript==
    
    const originalHrefDescriptor = Object.getOwnPropertyDescriptor(HTMLAnchorElement.prototype, 'href');
    window.addEventListener('DOMContentLoaded', () => {
      Object.defineProperty(HTMLAnchorElement.prototype, 'href', originalHrefDescriptor);
      // Now, assigning to .hrefs results in normal behavior again
    });
    

    Make sure to use // @run-at document-start to ensure your userscript runs before any code on the page runs - that way, you can save a reference to the descriptor before it gets overwritten.

    For this particular situation with wombat, you can also give the a a _no_rewrite property instead of saving the descriptor:

    const a = document.createElement('a');
    a._no_rewrite = true;
    a.href = 'https://www.google.com';