Monthly Archives: February 2012

You are browsing the site archives by month.

Cross-browser event hookup made easy

I seem to be on a roll. I’m coding and might as well be sharing some of what I’m working on while I do it. In that sense, here goes another small bit of code that I’ll be adding to jsSimple on github.

We all know how to hook up events cross-browser. We know that we have both attachEvent and addEventListener. Both have varying syntax and we’ve all written this code a million times. Let’s just make this simple. Here’s how to call this:

Event.add(element, 'click', callback, false);
// .. 
Event.remove(element, 'click', callback, false);

The remove looks like you’re passing around the same data, so I added a return value to “add” that allows you to capture the event and pass it in as a single object to the remove function as follows:

var evt = Event.add(element, 'click', callback, false);
// .. 
Event.remove(evt);

So, without further delay, here is the object definition:

/*!
 * jsSimple v0.0.1
 * www.jssimple.com
 *
 * Copyright (c) Tobin Titus
 * Available under the BSD and MIT licenses: www.jssimple.com/license/
 */
var EventObj = function (target, type, listener, capture) {
  return {
    'target' : target,
    'type' : type,
    'listener' : listener,
    'capture' : capture
  };
};

var Event = (function() {
  'use strict';
  function add (target, type, listener, capture) {
    capture = capture || false;
    if (target.addEventListener) {
      target.addEventListener(type, listener, capture);
    } else if (target.attachEvent) {
      target.attachEvent("on" + type, listener);
    }
    return new EventObj(target, type, listener, capture);
  }
  
  function remove(object, type, listener, capture) {
    var target;
    if (object && !type && !listener && !capture) {
      type = object.type;
      listener = object.listener;
      capture = object.capture;
      target = object.target;
    } else {
      capture = capture || false;
      target = object;
    }
    
    if (target.removeEventListener) {
      target.removeEventListener(type, listener, capture);
    } else if (target.detachEvent) {
      target.detachEvent("on" + type, listener);
    }
  }
  
  return {
    'add' : add,
    'remove' : remove
  };
}());

You can see this all in action on jsFiddle.

JavaScript animation timing made easy (requestAnimationFrame, cancelRequestAnimationFrame)

I often find myself writing a lot of the same code from project to project. One of those pieces of code is around using requestAnimationFrame and cancelRequestAnimationFrame. I wrote a quick and dirty animation object that allows me to register all of my rendering functions, start the animation and cancel it. Here’s an example of how to use this object:

function render () {
   // Do your rendering work here
}
Animation.add(render);
Animation.start();

It can also be used to add several animations before and even after Animation has started, you can add new rendering routines on the fly. This is useful in a number of instances where objects have their own render routines and you want to add rendering routines at different times.

I put in a few workarounds. The typical hack to allow setTimeout/cancelTimeout fallbacks are in there. There is also a work around to deal with the missing mozCancelRequestAnimationFrame and the fact that mozRequestAnimationFrame doesn’t return an integer per spec.

So here’s the code for the Animation object:

/*!
 * jsSimple v0.0.1
 * www.jssimple.com
 *
 * Copyright (c) Tobin Titus
 * Available under the BSD and MIT licenses: www.jssimple.com/license/
 */
var Animation = (function() {
  "use strict";
  var interval, moz, renderers = [];

// PRIVATE
  function __mozFix (val) {
    /* Mozilla fails to return interger per specification */
    if (!val) { 
      moz = true;
      val = Math.ceil(Math.random() * 10000);
    } 
    return val;
  }

  function __renderAll() {
    var r, length;

    // execute all renderers
    length = renderers.length;
    for (r = 0; r < length; ++r) {
       renderers[r]();
     }
     if (interval) {
       interval = __mozFix(window.requestAnimationFrame(__renderAll));
     }
   }
   function __registerAnimationEventHandlers() {
     var pre, prefixes = ['webkit', 'moz', 'o', 'ms'];
     // check vendor prefixes
     for (pre = prefixes.length - 1; 
          pre >= 0 && !window.requestAnimationFrame; --pre) {
      window.requestAnimationFrame = window[prefixes[pre] 
            + 'RequestAnimationFrame'];
      window.cancelAnimationFrame = window[prefixes[pre] 
            + 'CancelAnimationFrame'] 
            || window[prefixes[pre] + 'CancelRequestAnimationFrame'];
    }

    // downlevel support via setTimeout / clearTimeout
    if (!window.requestAnimationFrame) {
      window.requestAnimationFrame = function(callback) {
        // could likely be an adaptive set timeout
        return window.setTimeout(callback, 16.7);
      };
    }

    if (!window.cancelAnimationFrame) {
      window.cancelAnimationFrame = function(id) {
        clearTimeout(id);
      };
    }
  }
  __registerAnimationEventHandlers(); 

// PUBLIC
  function add(renderer) {
    if (renderer) {
      renderers.push(renderer);
    }
  }

  function isRunning() {
    return !!interval;
  }

  function start() {
    interval = __mozFix(window.requestAnimationFrame(__renderAll));
  }

  function stop() {
    if (!moz) {
      window.cancelAnimationFrame(interval);
    }
    interval = null;
  }

// OBJECT DEFINITION
  return {
    "add": add,
    "isRunning": isRunning,
    "start": start,
    "stop": stop
  };
}());

I’ve put this code on jsFiddle to test out.

I’ve also put this on github as jsSimple. I’ll likely add a few other bits of code to this as I move along.

CSS: Opacity vs Alpha (via rgba and hsla)

Once again, I was working on my new blog theme again and ran into the need to set the opacity of a background div without affecting the children. The support for opacity is spotty and slightly unpredictable. The other downside is that setting opacity via CSS affects the children of the transparent object. You can get around this by using an rgba background colors and specifying the alpha channel.

background-color: rgba(24, 117, 187, .5)

This specifies a background color of red: 24, blue: 117, green: 187 and an alpha of 50% transparency. I put up an example of this on jsFiddle here: http://jsfiddle.net/tobint/gazuB/

Here’s a side-by-side example of the differences between opacity and rgba.

Figure demonstrates opacity vs alpha

The div on the left has set an opacity of .5 on the div container. On the div on the right, I’ve set the background color with an alpha of .5 using rgba. Notice that the sample on the left has affected the transparency of the child div, but the sample on the right has not.

You can also set colors using hsla (hue, saturation, and lightness).

background-color: hsla(206, 77%, 41%, .5)

Of course, this only works in browsers released in the last few years:

  • Safari 3.1 in March 2008
  • Firefox 3 in June 2008
  • Chrome 4.0 in January 2010
  • Internet Explorer 9 in June 2011

Detecting CSS3 Transition Support

I’m in the process of developing a new blog theme for myself. I was trying to use CSS3 transitions but I wanted to fall back to JavaScript if transitions weren’t supported. I really want to avoid Modernizr if I can so I needed a quick and dirty test for detecting them. Here’s what I came up with:

var Detect = (function () { 
  function cssTransitions () { 
    var div = document.createElement("div"); 
    var p, ext, pre = ["ms", "O", "Webkit", "Moz"]; 
    for (p in pre) {
      if (div.style[ pre[p] + "Transition" ] !== undefined) {
        ext = pre[p]; 
        break; 
      } 
    } 
    delete div; 
    return ext; 
  }; 
  return { 
    "cssTransitions" : cssTransitions 
  }; 
}());

It’s simple and does the trick. Simply check the return of Detect.cssTransitions().

if (!Detect.cssTransitions()) {
   // Do JavaScript fallback here
}

You can also get the extension used in the current user-agent back from this method (ms, O, Moz, or Webkit).

Powershell: Selecting files that don’t contain specified content

I had a quick task today that required that I search a couple hundred directories and look in specific files to see if they contained a certain piece of code. All I wanted was the list of files that did not. PowerShell to the rescue!

I’ll break down each of the calls I used and provide the full command-line at the end for anyone interested.

First, we need to recurse through all the files in a specific directory. This is simple enough using Get-ChildItem.

Get-ChildItem -include [paths,and,filenames,go,here] -recurse

Next, I needed to loop through each of those files using ForEach-Object :

ForEach-Object { … }

Next, I need to get the content of each of those files. That’s done using Get-Content:

Get-Content [file]

I then need to be able to determine if the contents of the file contains the string I’m looking for. This is easy enough with Select-String:

Select-String -pattern [pattern]

That’s pretty much all the commands you need to know — we just need to put them together now.

PS> Get-ChildItem -include *.html,*.xhtml -recurse |
    ForEach-Object { if( !( select-string -pattern "pattern" -path $_.FullName) ) 
                     { $_.FullName}}