Report abuse


			
// Quick-and-dirty code for making a web page grayscale. Doesn't transform
// images, flash movies, or inline styles.  Requires Prototype >= 1.5.0.
// Tested in Firefox and nowhere else. (I was bored one Sunday afternoon.)

var Desaturator = {
  on: function() {
    $A(document.styleSheets).each(Desaturator.swapStyleSheet);
  },

  off: function() {
    Desaturator.styleNodes.each(Element.remove);
    Desaturator.styleNodes = [];
  },

  toggle: function() {
    if (Desaturator.styleNodes.length > 0) Desaturator.off();
    else Desaturator.on();
  },

  styleNodes: [],

  swapStyleSheet: function(sheet) {
    var media = sheet.ownerNode.getAttribute('media');
    if (media && media.indexOf('screen') == -1) return;

    var bwStyle = $A(sheet.cssRules).pluck('cssText').map(Desaturator.transform).join('\n');

    var style = document.createElement('style');
    style.appendChild(document.createTextNode(bwStyle));

    Desaturator.styleNodes.push(style);    
    document.getElementsByTagName('head')[0].appendChild(style);
  },

  transform: function(cssText) {
    return cssText.gsub(/rgb\(\d{1,3},\s*\d{1,3},\s*\d{1,3}\)(\b|\s|$|;)/, function(m) {
      return Desaturator.desaturate(m[0]);
    });
  },

  desaturate: function(str) {
    var m;
    if (m = str.match(/rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)(\b|\s|$|;)/)) {
      var values = m.slice(1, 4).map(function(val) { return parseInt(val, 10); });
      // take the average value of the R, G, and B channels and set each
      // channel to that value (quick but reliable way of desaturating)
      var v = Math.floor((values[0] + values[1] + values[2]) / 3);
      return new Template("rgb(#{v}, #{v}, #{v})").evaluate({ v: v }) + m[4];
    }
  }
};

Event.observe(window, 'load', function() {
  $('toggleDesaturation').observe('click', Desaturator.toggle);
});