Archive for July, 2009

Just a general note, you can’t delete everything

I’ve had this discussion a couple of times now with several people and maybe It’s about time to make a post for it here 🙂

The delete operator in ECMAScript-262 can only be used to delete dynamically created variables/properties. Having that said heres a code sample:

var foo = "test"; //executing this in the global window-scope will actually create window.foo and it's being considered as a  dynamically created property on the window object.
delete foo;  //will return true, success
alert(foo); //throws a javascript exception since foo is deleted, thus being undefined

On the other hand…

(function(){
var foo ="test";  //local to the anonymous function, could as well be in a named function.
delete foo;  //will return false, failure to delete
alert(foo);  //will alert "test", delete had no affect
})();

1 Comment

Dispatcher followup : A more compact way of writing prototypes + module pattern + test

The previous post I added some prototype methods to the Dispatcher class, but It could has well been written on the following syntax instead

function Dispatcher(){}
Dispatcher.prototype = {
     addEventlistener : function(event, callback){
        //code here
     },
     removeEventlistener : function(event, callback){
        //code here
     }
     //add more methods here... don't forget to comma-separate them and do not add a comma last!
}

So how about writing up this with the module pattern on the same time. I’ll also show a simple way to write an automatic unit-alike test for this.

/**
* @author: Erik Karlsson, www.nonobtrusive.com
**/
var nonobtrusive = nonobtrusive ||{}; //create the "namespace" like object if it doesnt exist
nonobtrusive.events = nonobtrusive.events || {}; //create the sub-namespace events where we'll place our Dispatcher class
nonobtrusive.events.Dispatcher = (function(){
	var undefined; //speed up references to undefined + allows munging
    function Dispatcher(){
         this.events=[];
    }
    Dispatcher.prototype = {
		addEventlistener : function(event, callback){
			if ( event == undefined || callback == undefined ) return false;	//verify that we have parameters sent in
			var listeners = this.events[event] = this.events[event] || [];		//create a new array to hold listeners if first time
			listeners[listeners.length]=callback;
		},
		removeEventlistener : function(event, callback){
			if ( event == undefined || callback == undefined ) return false;	//verify that we have parameters sent in
			var listeners = this.events[event];
			if ( listeners ) {
				for ( var i = listeners.length-1; i>=0; --i ){	//go through all listeners for this specific event
					if ( listeners[i] === callback ) {
						listeners.splice( i, 1 );	//remove the eventcallback if we found it
						return true;
					}
				}
			}
			return false;
		},
		dispatch : function(event){
			if ( event == undefined ) return false;
			if ( this.events[event] ) {
				var listeners = this.events[event], len = listeners.length;
				while ( len-- ) {
					listeners[len](this);	//callback with self
				}		
			}
		}
		//add more methods here... don't forget to comma-separate them and do not add a comma last!
   }
 
   return Dispatcher;
})();
 
 
function DispatcherTest(){
	nonobtrusive.events.Dispatcher.call(this);
 
	//Some internal variables to keep track of the test-process.
	var	dispatchOk = false,
		afterRemovalOk = false;
 
	this.dispatchCallback = function(){
		dispatchOk = !dispatchOk;
	}
 
	this.setup = function(){
		this.addEventlistener("TestEvent", this.dispatchCallback);
	}
 
	this.run = function(){
		this.dispatch("TestEvent");
		afterRemovalOk = this.removeEventlistener("TestEvent", this.dispatchCallback);
		this.dispatch("TestEvent");	//nothing should happen since we're not listening to this event anymore.
		if ( dispatchOk && afterRemovalOk ) {
			alert("DispatcherTest was ok!");
		}
	}
}
DispatcherTest.prototype = new nonobtrusive.events.Dispatcher();
 
//Run the test
var test = new DispatcherTest();
test.setup();
test.run();

If you want to use this class, download the minified script here :
http://www.nonobtrusive.com/wp-content/uploads/2009/07/nonobtrusive.events.Dispatcher-min.js
or try out the test yourself by visiting this page :
http://www.nonobtrusive.com/wp-content/uploads/2009/07/dispatcher-test.html

, , , , ,

1 Comment

Custom events in javascript by making your own Dispatcher class.

Don’t have the time to comment the code and explain right now, but I will update the post later on 🙂
I wrote this in about 2minutes to help out a guy just before going to bed so I’ve only tested the addEventListener and dispatch functionality (not removeEventListener), but it actually worked in IE7, IE8, Firefox 3.5, Chrome2 and Stainless (Webkit based browser under osx) on the first try.

Feel free to comment if you find this useful

/**
* @author Erik Karlsson, www.nonobtrusive.com
*/
function Dispatcher(){
	this.events=[];
}
Dispatcher.prototype.addEventlistener=function(event,callback){
	this.events[event] = this.events[event] || [];
	if ( this.events[event] ) {
		this.events[event].push(callback);
	}
}
Dispatcher.prototype.removeEventlistener=function(event,callback){
	if ( this.events[event] ) {
		var listeners = this.events[event];
		for ( var i = listeners.length-1; i>=0; --i ){
			if ( listeners[i] === callback ) {
				listeners.splice( i, 1 );
				return true;
			}
		}
	}
	return false;
}
Dispatcher.prototype.dispatch=function(event){
	if ( this.events[event] ) {
		var listeners = this.events[event], len = listeners.length;
		while ( len-- ) {
			listeners[len](this);	//callback with self
		}		
	}
}
 
 
/** Below is some test-code to verify the most basic functionality **/
function SomeClass(){
	Dispatcher.call(this);
}
SomeClass.prototype = new Dispatcher();
 
SomeClass.prototype.sendSomeEvent=function(){
	this.dispatch("test");
}
 
var foo = new SomeClass();
foo.addEventlistener( "test", function(){ alert("bah"); } )
foo.sendSomeEvent();

, ,

17 Comments

Count the number of javascript eventhandlers in the DOM-tree.

Sometimes I’ve wanted to find out how many eventhandlers there are attached to the DOM-tree I’m working with, but I’ve never found a good tool for doing this. I decided to write a simple javascript snippet that traverses the tree and finds the fact for me and it looks like its working pretty good too.

Please don’t hesitate to comment if you find this useful or have any improvement suggestions

/**
* @author Erik Karlsson, www.nonobtrusive.com
**/
function countEventHandlers(){
 
var elements = document.getElementsByTagName("*"), len = elements.length,
     counter = 0,
     countermap = [],
     /* fill up with more events if needed or just use those you want to look for */
     events = ['onmousedown', 'onmouseup', 'onmouseover', 'onmouseout', 
                   'onclick', 'onmousemove', 'ondblclick', 'onerror', 'onresize', 'onscroll',
                   'onkeydown', 'onkeyup', 'onkeypress', 'onchange', 'onsubmit'], 
     eventlen = events.length;
 
for ( var i = eventlen-1; i >= 0; --i ) {
    countermap[events[i]] = 0;   //reset the map
}
 
 
while ( len-- ) {  //go through all DOM-nodes
    var element = elements[len],
        tmp = eventlen;
    while ( tmp-- ) {  //go through all events defined above for each node and see if it exists.
        if ( element[events[tmp]] ) {
            counter++;
            countermap[events[tmp]]++;
        }
    }    
}
 
var someStats = counter + " events found in total\n\n";
for ( var o in countermap ) {
   someStats += o + " was found " + countermap[o] + " times\n";
}
alert(someStats);
 
}

, , , , , ,

1 Comment

So you think you’re writing effiecent jQuery selectors?

Think again if you’re writing selectors such as

$("div#myId")

When selecting against the DOM ID the fastest way to get the node is to use only the id:

$("#myId") //will translate into document.getElementById("myId") internally

otherwise jQuery will first get all DIV-nodes then manually iterate over them looking for an attribute id that’s equal to “myId”. In a case with a large DOM-tree this could be a large performance-hit making your site unusable on slower computers if you’re using selectors like this everywhere.

On the other hand when selecting against CSS-classes it’s faster to use

$("div.myClass")

than just

$(".myClass")

,

2 Comments

Strict standards could break admin css in wordpress

The following method in class.wp-scripts.php could break your css if you have strict standards enabled on your server.

	function set_group( $handle, $recursion, $group = false ) {
		$grp = isset($this->registered[$handle]->extra['group']) ? (int) $this->registered[$handle]->extra['group'] : 0;
		if ( false !== $group && $grp > $group )
			$grp = $group;
 
		return parent::set_group( $handle, $recursion, $grp );
	}

This is because the WP_Scripts inheritance from WP_Dependencies does not follow the signature of the method. WP_Dependencies have the set_group function declared without any default parameters while the subclass have defaulted $group to false.

Easy fix! Just remove the default value on the group parameter so it looks like this:

	function set_group( $handle, $recursion, $group ) {
		$grp = isset($this->registered[$handle]->extra['group']) ? (int) $this->registered[$handle]->extra['group'] : 0;
		if ( false !== $group && $grp > $group )
			$grp = $group;
 
		return parent::set_group( $handle, $recursion, $grp );
	}

The only place I can find this possible being called from send in a value anyway so there’s no need for having the default value as of right now.

5 Comments

How to get the amount of days in an arbitrary month with leapyear in consideration

function daysInMonth( month, year ) {
       var now  = new Date();
       month = month || now.getMonth()+1; //this month as default
       year = year || now.getFullYear();    //this year as default
       return new Date(year, month, 0).getDate();
}
 
//consider January as month 1, February as month 2 ... December 12
 
daysInMonth( 2, 2003 ); //returns 28, not leap-year
daysInMonth( 2, 2004 ); //returns 29, leap-year
daysInMonth( 7, 2009 ); //returns 31
daysInMonth( ); //returns the amount of days in the current month

, , , ,

3 Comments