Internet Explorer Event Handler Leaks

If you’ve been developing for the open web for long, you’ll know that Internet Explorer is the bane of any web developer’s existence. The number of CSS bugs are enough to give any web developer a headache, but then add to that JScript’s deviations from the ECMAScript 3 spec and you have yourself a pain in the neck as well. Grab your favorite pain reliever, because there is another nuisance: memory leaks.
Read more ›

Posted in Code Tagged with: ,

Adding Axis Titles to DojoX Charts

DojoX charting is a very powerful 2D graphics charting solution that works cross-browser. One thing that is an often requested feature is axis titles. I’ve come up with a solution (inspired by a post on the old Dojo forums) that leverages the current API and renders correctly in all browsers. I’ll be using Dojo 1.5 from Google’s CDN plus a local module as I outlined in my local module with a CDN build tutorial.

my/Chart2D.js

dojo.provide("my.Chart2D");
 
dojo.require("dojox.charting.Chart2D");
 
dojo.declare("my.Chart2D", dojox.charting.Chart2D, {
	render: function(){
		this.inherited(arguments);
		var axes = this.axes,
			theme_tick = this.theme.axis.tick,
			theme_font = theme_tick.font,
			theme_font_color = theme_tick.fontColor,
			dim = this.dim,
			offsets = this.offsets,
			x_middle = (dim.width / 2) + (offsets.l / 2),
			y_middle = (dim.height / 2) - (offsets.b / 2),
			m = dojox.gfx.matrix;
 
		// For each axis defined, loop through, check if there
		// is a 'title' property defined.
		for(var i in axes){
			var axis = axes[i];
			if(axis.opt.title){
				var x, y,
					rotate = 0;
 
				// If the axis is vertical, rotate it
				if(axis.vertical){
					rotate = 270;
					y = y_middle;
					x = 12;
				}else{
					x = x_middle;
					y = dim.height - 2;
				}
 
				// Render the text in the middle of the chart
				var elem = axis.group.createText({
					x: x_middle,
					y: y_middle,
					text: axis.opt.title,
					align: 'middle'
				});
 
				// Set the font and font color
				elem.setFont(
					axis.opt.font || theme_font
				).setFill(
					axis.opt.fontColor || theme_font_color
				);
 
				// If the axis is vertical, rotate and move into position,
				// otherwise just move into position.
				if(rotate){
					elem.setTransform([
						m.rotategAt(rotate, x_middle, y_middle),
						m.translate(0, x - x_middle)
					]);
				}else{
					elem.setTransform(m.translate(0, y - y_middle))
				}
			}
		}
	}
});

This is pretty straight-forward: the code figures out where the middle of the axes are and places the title there, rotating if necessary. I’ll point out one important part: the text must initially be created in the middle of the chart and then translated into position. If the text is created where it should be placed, WebKit-based browsers will hide the vertical axis’ title because it initially renders partially off-screen.

You use this new class exactly like you would use dojox.charting.Chart2D, except that each axis can now be passed a title attribute:

new my.Chart2D('chartNode').
	setTheme(dojox.charting.themes.PlotKit.cyan).
	addPlot("default", {
		type: "Default",
		lines: true,
		markers: true,
		tension: 2
	}).
	addAxis("x", {
		title: 'X Axis',
		min: 0,
		max: 6,
		majorTick: { stroke: "black", length: 3 },
		minorTick: { stroke: "gray", length: 3 }
	}).
	addAxis("y", {
		title: 'Y Axis',
		vertical: true,
		min: 0,
		max: 10,
		majorTick: { stroke: "black", length: 3 },
		minorTick: { stroke: "gray", length: 3 }
	}).
	addSeries("Series A", [
		{ x: 0.5, y: 5 },
		{ x: 1.5, y: 1.5 },
		{ x: 2, y: 9 },
		{ x: 5, y: 0.3 }
	]).
	addSeries("Series B", [
		{ x: 0.3, y: 8 },
		{ x: 4, y: 6 },
		{ x: 5.5, y: 2 }
	]).
	render();

Chart with axis titles

I’ve posted a live example, a tarball, and a zip file for download. As you can see, DojoX charting is quite powerful on its own but is easily extensible.

Posted in Code Tagged with: , , ,

Using Local Modules With a Cross-Domain Dojo Build

Lately, I have been using Dojo from a CDN as much as possible. There are several reasons to use a cross-domain build of Dojo that are listed here:

  1. You get more connections in MSIE, since you can load from another domain. Faster loading.
  2. You get increased cacheability/startup if many of your applications use the same installation.
  3. Resource loading does not block the rest of the page from filling in as with Dojo’s normal, synchronous loading.
  4. With a local install, your ISP may otherwise charge you for all of those Dojo bits that you are serving.

The one problem with using a CDN is that you don’t have control over the build, which means you can’t build custom code into it. Building custom code into a build is what most people do with builds, so it would seem you can’t develop code using Dojo’s module system against a CDN. This couldn’t be farther from the truth.

In this post, we’re going to be using Dojo from AOL’s CDN. This method can also be used against a custom cross-domain build. It may not seem like that would be very useful, but you may need to develop a new custom module against your build and don’t want to rebuild to test each change you make. Let’s look at the source:

xdlocal.html

<!DOCTYPE HTML>
<html>
<head>
	<title>XDomain Build With Local Modules</title>
	<style type="text/css">
		@import "http://o.aolcdn.com/dojo/1.4.3/dijit/themes/tundra/tundra.css";
	</style>
	<script type="text/javascript">
		var djConfig = {
			isDebug: true,
			parseOnLoad: true,
			baseUrl: './',
			modulePaths: {
				'my': 'my'
			}
		};
	</script>
	<script type="text/javascript" src="http://o.aolcdn.com/dojo/1.4.3/dojo/dojo.xd.js"></script>
	<script type="text/javascript">
		dojo.require("my.Foo");
	</script>
</head>
<body class="tundra">
	<button dojoType="my.Foo">
		This is a "my.Foo" button.
	</button>
</body>
</html>

my/Foo.js

dojo.provide("my.Foo");
 
dojo.require("dijit.form.Button");
 
dojo.declare("my.Foo", dijit.form.Button, {
	onClick: function(){
		alert('Button clicked!!');
	}
});

I have also provided a live example as well to show it working. You can grab the source files in a tarball or zip file as well so you can play around with it.

The key part here is in the HTML file:

<script type="text/javascript">
	var djConfig = {
		isDebug: true,
		parseOnLoad: true,
		baseUrl: './',
		modulePaths: {
			'my': 'my'
		}
	};
</script>
<script type="text/javascript" src="http://o.aolcdn.com/dojo/1.4.3/dojo/dojo.xd.js"></script>

djConfig is used to configure Dojo upon loading. The modulePaths object tells where to find the modules relative to baseUrl. Changing baseUrl does not affect the URL used for dojo, dijit, or dojox because those are hard-coded in the cross-domain build. The main thing to remember is that baseUrl must end in a /. Given this information, we can deduce that I am telling Dojo that the my modules can be found at http://www.reigndropsfall.net/demos/xdlocal/my/.

As you can see from this simple example, Dojo’s module system is very versatile. Not only can you host a build, host a custom build, host a cross-domain build, or use a CDN, but you can combine cross-domain builds with local modules which can save time and bandwidth costs.

Posted in Code Tagged with: , , , ,

Monkey patching

Recently, David Walsh tweeted that I had schooled him. I received several questions about what I had schooled him in, so I decided to blog about it.

David was trying to change the behavior of a method of a widget on a page, but for all instances of that widget rather than just one instance. What follows is a lesson on monkey patching. I’m sure there are other tutorials out there about it, but this is more for my sanity (and to get David off my back about blogging) than anything else.

Wikipedia defines Monkey patching as “a way to extend or modify the runtime code of dynamic languages (e.g. Smalltalk, JavaScript, Objective-C, Ruby, Perl, Python, Groovy, etc.) without altering the original source code.” For our purposes, we’ll only be looking at JavaScript. Wikipedia also lists four uses for monkey patching:

  • Replace methods/attributes/functions at runtime.
  • Modify/extend behavior of a third-party product without maintaining a private copy of the source code.
  • Apply a patch at runtime to the objects in memory, instead of the source code on disk.
  • Distribute security or behavioral fixes that live alongside the original source code.

In the JavaScript world, monkey patching can be very important if you’re using a third-party library. This is especially true if you are using it from a CDN or are checking it out from a version control system. We’ll use this HTML as our test page and use Dojo from the AOL CDN:

< !DOCTYPE HTML>
<html>
<head>
	<title>A Monkey-patching example</title>
	<script type="text/javascript" src="http://o.aolcdn.com/dojo/1.4.3/dojo/dojo.js"></script>
	<script type="text/javascript">
		dojo.ready(function(){
			dojo.declare("Adder", null, {
				constructor: function(base){
					this._base = base;
				},
 
				add: function(what){
					return this._base + what;
				}
			});
		});
	</script>
</head>
<body>
</body>
</html>

I will assume basic knowledge of JavaScript, object prototype chains, and dojo.declare. The code examples that follow can be pasted into your browser’s JavaScript console (such as Firebug).

Monkey patching object instances

Let’s say you have an Adder instance and you’d like to change the calculation that happens when calling add(). Simply add an add method to the object instance:

var myAdder = new Adder(5);
myAdder.add(5); // returns 10
myAdder.add = function(what){
	return what + 20;
};
myAdder.add(5); // returns 25

That’s all well and good, but how do we perform the original add calculation, yet modify it without rewriting the method completely? Just store the add method to a variable, add an add method to the object instance, and call the stored add method within the new add method. You’ll generally also want to wrap that all in a closure so only the new method can access the old method. Confused yet? Don’t be:

var myAdder2 = new Adder(5);
myAdder2.add(5); // returns 10
(function(){
	var oldAdd = myAdder2.add;
	myAdder2.add = function(what){
		return oldAdd.call(this, what) + 20;
	};
})();
myAdder2.add(5); // returns 30

One note

You might have noticed that I didn’t use the word “overwrite” when talking about monkey patching object instances. This is because object instances look up their properties from their prototype unless explicitly defined on them (like _base). This is what one might call “masking” and is an important concept in JavaScript. When we were monkey patching before, we were actually masking the add method on the Adder prototype (it’s a subtle difference, but important).

Monkey patching an object’s prototype

Great! We can modify individual instances. But let’s say we have 30 Adder instances and we don’t want to modify them all every time. This is where monkey patching the prototype comes in:

var myAdder3 = new Adder(5);
myAdder3.add(5); // returns 10
Adder.prototype.add = function(what){
	return this._base + what + 10;
};
myAdder3.add(5); // returns 20

Here, we’re overwriting (instead of masking) the add method. This applies to instances already created that haven’t had their methods masked (try myAdder.add(5); and myAdder2.add(5);) and future created instances. As we did before, you can also call the originally defined method:

var myAdder4 = new Adder(5);
myAdder4.add(5); // returns 20
(function(){
	var oldAdd = Adder.prototype.add;
	Adder.prototype.add = function(what){
		return oldAdd.call(this, what) + 10;
	};
})();
myAdder4.add(5); // returns 30
myAdder3.add(5); // returns 30

Note how myAdder3 is also affected by this new monkey patch. As you can see, monkey patching is quite simple yet very powerful. Although I used dojo.declare, this can be used to modify any JavaScript object or prototype chain: you can modify a widget’s behavior, add debugging output to a method, or even modify arguments passed to the original function.

Posted in Code Tagged with: , , ,

Back from hiatus

It’s been a long long time since I’ve seriously blogged and I’m going to get back into it again (at the behest of David Walsh). I’ve got a couple of tutorials and/or tips lined up and I intend to keep up with it. Alright, back to your regularly scheduled programming…

Posted in General

Recipe for Brye

A few people have asked me for this after I made mention of it in my status updates. This is a Forbes-family treat that is great when you’re feeling crummy. We used to have it all the time when I was a kid and we were home from school. I just learned the other night that it’s actually a dessert (I would never have guessed). Anyway, here is the recipe for Brye:

Ingredients:
2 cups milk
1/2 cup sugar
1/4 cup flour
pinch of salt
1 tsp vanilla
1 egg
2 tbsp butter

Directions:
Put the sugar and flour into a medium saucepan. Measure the milk in a glass measuring cup and pour into saucepan. In the same measuring cup, whisk the egg and pour into saucepan. Bring to a boil. Add the butter, vanilla, and salt and stir until it thickens. Let it cool a bit before partaking!

Posted in General Tagged with: ,

A petition to take back our freedoms

I know it’s been a long time since I’ve written a real blog post, but I wanted to make sure everyone knew about this: A petition to bring articles of impeachment against the Bush administration. If you have the time, please read the articles. For those of you who don’t like to read and would rather watch something (or even listen to it), please check out these links:

Hearing on Limits of Executive Power: Dennis Kucinich
Hearing on Limits of Executive Power: Bruce Fein
Hearing on Limits of Executive Power: Vincent Bugliosi
Hearing on Limits of Executive Power: Robert Wexler

I want to let everyone know that I’m not a war for oil, moveon.org, or Bush==Hitler person. I voted for Bush in 2000 and 2004. I supported the Bush administration’s decision to go into Afghanistan to fight Al-Qaeda. I even bought the need to go into Iraq. But I’m also a person who believes that if you make a mistake, you don’t cover it up: you own up. I believe that when an someone abuses the power they have been given, they need to be held accountable. I urge you to read the articles of impeachment and watch the clips and decide for yourself.

Posted in Politics Tagged with: , ,

If you support our troops…

I know I’m way overdue for an update, but I had to post this. I’ve also tried to stay out of the political posting this season, but I thought I’d post this. The mainstream media has done an excellent job of squelching a fine candidate: Ron Paul. Yes, he has very libertarian stands and that’s what appeals to me: he believes that the federal government should only take care of what is outlined in the constitution. It seems like his message is resonating with our troops (warning: Flash content follows… I’m not a big fan of proprietary technology, but I feel like this needs to be spread):

Via Daily Paul.

Posted in General, Politics Tagged with:

Through field and barbed wire

So last night, Asaph’s Apprentice drove down to Lamoine Christian Service Camp last night to play a show. It wouldn’t have been too much of a hassle, except that we got our directions from MapQuest (no link love for them… you’ll soon see why).

Here are the directions we used. Note directions #14 and #16. Right turns on CR-2800… easy enough. Or so we thought. The first turn onto CR-2800 goes through some guy’s field and ends up where the directions say it should. The second turn onto CR-2800 is a little more misleading. If you click on the map link for direction #16, it shows you a nice straight road… this is not what CR-2800 currently looks like. We ended up driving through another field and ended at a barbed wire fence. I wish we would have taken a picture… it was priceless. Thank you MapQuest.

Of course, Google Maps doesn’t get it any better and Rand McNally fails miserably as well. The only directions site that gives directions that don’t end up in the middle of nowhere (literally) is Yahoo! Maps. And their directions end up taking less time too.

What is it with these map sites? Why don’t they have a review feature? It ended up taking us an hour more to get to the camp because we had to backtrack out of the field (while bottoming out a couple of times) and then flagging down someone who’s first question to us was, “Are you guys looking for the camp?” If we hadn’t have planned to get there 2 hours early, we would have been late. And yes, I know that all of these map sites have their little disclaimer that says something to the effect of “if these directions suck and you end up in the middle of a field or lake or get eaten by cannibals it’s not our fault,” but seriously… it’d be nice to be able to get alternate routes from people that actually live in the place that you’re going to or have been there before.

Posted in General Tagged with:

Don’t Panic!!!

Today is Towel Day. That is all for now.

Posted in General Tagged with: