Supports Webmentions? Bookmarklet

I’ve found myself wanting to check if a webpage supports webmentions while internetting, so I made a bookmarklet for it.

Often I want to know if a page supports webmentions, so I know if I should respond only from my website or directly on that page.

On a desktop browser I can inspect the response headers and page source for a webmention endpoint. But it’s a little bit of work and something I can't do at all on my phone. So I made this little bookmarklet:

Supports Webmentions?

Drag that to your bookmark bar, or if you’re on iOS, copy the below JavaScript, create a new bookmark (Share Icon > Add Bookmark), change the name to “Supports Webmentions?”, and paste the copied javascript as the URL address for the bookmark.

Here it is in a more readable format (also on Github):

javascript: (() => {
  // Set some strings for the common result scenarios.
  const support = "Page supports webmentions!";
  const noSupport = "Page does not support webmentions :(";

  // Create a dialog element and insert into the DOM.
  let d = document.createElement('dialog');
  document.getElementsByTagName('body')[0].appendChild(d);

  // Remove the dialog element when it's closed.
  d.addEventListener('close', () => {
    d.remove();
  });

  // Create the contents of the dialog.
  let content = document.createElement('p');
  let close = document.createElement('form');
  close.method = 'dialog';
  close.innerHTML = "<button>Close</button>";

  // Insert into the dialog element.
  d.appendChild(content);
  d.appendChild(close);
  
  // Go ahead and set the initial status and show the dialog as a modal.
  content.innerHTML = "Checking page source for <code>link[rel~=webmention]</code> or <code>a[rel~=webmention]</code>…";
  d.showModal();

  // The official spec (https://www.w3.org/TR/webmention/#sender-discovers-receiver-webmention-endpoint) calls for 
  // checking for a Link HTTP header first, and then for these elements in the source. Since we don't care about 
  // finding the correct webmention endpoint, only if one exists, we can check source first and potentially save 
  // an HTTP request.

  // Get all `link` and `a` elements that have a `rel` attribute containing "webmention".
  let els = document.querySelectorAll('link[rel~=webmention], a[rel~=webmention]');

  // If any of those elements exist, the page supports webmentions.
  if (els.length > 0) {
    content.innerHTML += '<br/>Page source contains <code>link[rel~=webmention]</code> or <code>a[rel~=webmention]</code>!<br/><br/>' + support;
    return;
  }

  // If none exist, check the Link HTTP header.
  content.innerHTML += '<br/>Page source does not contain <code>link[rel~=webmention]</code> or <code>a[rel~=webmention]</code>.<br/><br/>Checking page for Link HTTP header…';

  // Make a HTTP request for the current page.
  let location = window.location;

  fetch(location).then((response) => {
    // If the response does not have a Link header, then this page does not support webmentions.
    if (!response.headers.has("Link")) {
      content.innerHTML += '<br/>Page does not have a Link HTTP header.<br/><br/>' + noSupport;
      return;
    }

    // The Link header can contain multiple values, separated by commas.
    let links = response.headers.get("Link").split(",");

    // If no links, then the Link header is empty and the page does not support webmentions.
    if (links.length <= 0) {
      content.innerHTML += '<br/>Link HTTP header is empty.<br/><br/>' + noSupport;
      return;
    }

    // Iterate over the links, checking each one for a `rel=webmention` value. If one exists, then the page
    // supports webmentions.
    for (let link of links) {
      if(/;\s*rel=["']?webmention["']?/.test(link)) {
        content.innerHTML += '<br/>Page has a Link HTTP header with `rel="webmention"`.<br/><br/>' + support;
        return;
      }
    }

    // Otherwise the page does not support webmentions.
    content.innerHTML += '<br/>Page does not have a Link HTTP header with `rel="webmention"`.<br/><br/>' + noSupport;
  }).catch(e => {
    // Output any errors from the Link header check to the dialog.  
    content.innerHTML += "<br/><br/>Error checking for Link header: " + e;
  });
})();

I’m not completely happy with the HTTP header regex. While it will match rel=webmention, rel="webmention", and rel='webmention', it won’t match rel values with more than one space-delimited value, which I think is technically valid syntax.

I’ve tested it against the Webmention Rocks test suite, and it passed all of those scenarios.

P.S. This is a convenient tool for escaping the JavaScript for embedding a bookmarklet as the href of an anchor element.