Canonical Url Generation and Insertion

By Chris Roos Last update Apr 15, 2009 — Installed 74 times.
// ==UserScript==
// @name          Canonical Url Generation and Insertion
// @namespace     http://chrisroos.co.uk/
// @description   A script that allows me to construct rules to determine the permalink of a given URL and write that permalink into the page as a link element with rel=canonical.
// @include       *
// ==/UserScript==

// **********************************************
// CanonicalUrl members

CanonicalUrl = {
  
  utilities : {
    queryString : function(location) {
      var keysAndValues = {};
      if (m = location.href.match(/\?(.*)/)) {
        var queryString = m[1];
        var keyValuePairs = queryString.split('&');
        if (keyValuePairs.length > 0) {
          for (var i = 0; i < keyValuePairs.length; i++) {
            var key = keyValuePairs[i].split('=')[0];
            var value = keyValuePairs[i].split('=')[1];
            if (key)
              keysAndValues[key] = value;
          }
        }
      }
      return keysAndValues;
    },
    insertCanonicalLink : function(href) {
      var canonicalLink = document.createElement('link');
      canonicalLink.setAttribute('rel', 'canonical');
      canonicalLink.setAttribute('href', href);
      var head = document.getElementsByTagName('head')[0];
      head.appendChild(canonicalLink);
    }
  },
  
  urlRewriters : {
    requiredKey : function(url, key) {
      if (key && url.queryString && url.queryString[key]) {
        var queryString = [key, url.queryString[key]].join('=');
        return url.protocol + '//' + url.host + url.pathname + '?' + queryString;
      } else {
        return '';
      }
    }
  },
  
  Url : function(location) {
    this.hash = location.hash;
    this.host = location.host;
    this.hostname = location.hostname;
    this.href = location.href;
    this.pathname = location.pathname;
    this.port = location.port;
    this.protocol = location.protocol;
    this.search = location.search;
    this.queryString = CanonicalUrl.utilities.queryString(location);
  },
  
  Permalink : function(location) {
    this.location = location;
  },
  
  Rule : function(urlPattern, urlRewriter) {
    this.urlPattern = urlPattern;
    this.urlRewriter = urlRewriter;
  },
  
  RuleCollection : function() {
    this.rules = [];
  },
  
  insert : function(location) {
    var permalink = new CanonicalUrl.Permalink(location);
    if (href = permalink.href())
      CanonicalUrl.utilities.insertCanonicalLink(href);
  }
  
}

// **********************************************
// CanonicalUrl member prototypes

CanonicalUrl.Permalink.prototype = {
  href : function() {
    return CanonicalUrl.Rules.apply(this.location);
  }
}

CanonicalUrl.Rule.prototype = {
  rewriteUrl : function(url) {
    if (this.urlPattern.test(url.href)) {
      if (this.urlRewriter && typeof(this.urlRewriter) == 'function')
        return this.urlRewriter(url);
    }
  }
}

CanonicalUrl.RuleCollection.prototype = {
  add : function(urlPattern, urlRewriter) {
    var rule = new CanonicalUrl.Rule(urlPattern, urlRewriter);
    this.rules.push(rule);
  },
  apply : function(location) {
    for (var i = 0; i < this.rules.length; i++) {
      var rule = this.rules[i];
      var url = new CanonicalUrl.Url(location);
      if (rewrittenUrl = rule.rewriteUrl(url))
        return rewrittenUrl;
    }
  }
}

// **********************************************
// The actual real-life rules

CanonicalUrl.Rules = new CanonicalUrl.RuleCollection();
CanonicalUrl.Rules.add(/userscript_integration_matching_rule_test\.html/, function(url) { 
  return 'userscript-permalink';
});
CanonicalUrl.Rules.add(/google\.co\.uk\/search/, function(url) { 
  return CanonicalUrl.urlRewriters.requiredKey(url, 'q');
});
CanonicalUrl.Rules.add(/theyworkforyou\.com\/wrans/, function(url) { 
  return CanonicalUrl.urlRewriters.requiredKey(url, 'id');
});
CanonicalUrl.Rules.add(/cgi\.ebay\.co\.uk/, function(url) {
  var hash = url.queryString.hash;
  if (m = hash.match(/item(\d+)/)) {
    var itemId = m[1];
    return 'http://cgi.ebay.co.uk/ws/eBayISAPI.dll?ViewItem&item=' + itemId;
  }
});

// **********************************************
// Do the magic
CanonicalUrl.insert(document.location);