Saturday, March 31, 2007

My Javascript addEvent

In the end of 2005 several web programming gurus, Peter-Paul Koch (ppk), Dean Edward and Scott Andrew LePera host a "javascript recoding contest" in which they asked participants to submit their code for adding and removing events in javascript. A template page was designed to test the code. The winner was John Resig, whose original code is here. The final code was slightly modified version:

function addEvent( obj, type, fn )
{
if (obj.addEventListener)
obj.addEventListener( type, fn, false );
else if (obj.attachEvent)
{
obj["e"+type+fn] = fn;
obj[type+fn] = function() { obj["e"+type+fn]( window.event ); }
obj.attachEvent( "on"+type, obj[type+fn] );
}
}
function removeEvent( obj, type, fn )
{
if (obj.removeEventListener)
obj.removeEventListener( type, fn, false );
else if (obj.detachEvent)
{
obj.detachEvent( "on"+type, obj[type+fn] );
obj[type+fn] = null;
obj["e"+type+fn] = null;
}
}

I personally don't feel comfortable with these code. First of all, as one of the comments mentioned (#2 Posted by Tino Zijdel on 18 October 2005) that in cases of multiple-eventhandlers in IE, the eventhandler added last will be executed first:

... since this is for IE a wrapper around attachEvent, the execution order of the events is different ('random' according to Microsofts documentation, but LIFO in practice against FIFO using the W3C event model)

A simple test reveals this problem:

function init(){
var btn=document.createElement('input')
btn.value = 'Click me'
btn.type = 'button'
document.body.appendChild( btn )
addEvent( btn, "click", function(){alert("#1")} )
addEvent( btn, "click", function(){alert("#2")} )
}

Run the init() function as the onload eventhandler (<body onload="init()">) and load with browser. Firefox alerts "#1" then "#2". But IE alerts "#2" first then "#1", which is not what it should be.

Another part making me uncomfortable is that it uses the entire function content as the key name of a hash:

   obj["e"+type+fn] = fn;
obj[type+fn] = function() { obj["e"+type+fn]( window.event ); }

Although none obvioiusly problem is mentioned or discussed, it could result in extremely long and complex key name, which, IMHO, is not what a hash is supposed to be.

I therefore came up with my own version:

function addEvent( obj, type, fn ) 
{
obj.eventHooks = obj.eventHooks || {} // set .eventHooks for obj if not exists
var evs = obj.eventHooks[type] || [] // set .eventHooks[type] if not exists
obj.eventHooks[type] = evs.concat( fn.concat? fn:[fn]) // this allows for multiple fns added
obj['on'+type] = function (e) // like addEvent(obj,"click",[f1,f2])
{
for (var i=0;i<this.eventHooks[type].length;i++)
{
this.tmp = this.eventHooks[type][i] // attach to the obj such that the this
this.tmp(e) // inside the function points to the obj correctly
this.tmp = undefined
}
}
obj = null
}
function removeEvent( obj, type, fn )
{
if (obj.eventHooks && obj.eventHooks[type])
{
var evs = obj.eventHooks[type]
for (var i=0; i<evs.length;i++)
{
if (evs[i]==fn)
{
obj.eventHooks[type] = evs.slice(0,i).concat(evs.slice(i+1))
break
}
}
}
obj = null
}

Unlike most addEvent inventions, in which either addEventListener or attachEvent is used, the above code simply stores eventhandlers into a buffer that has the following structure:

  obj.eventHooks = { click    : [f1, f2]
, keyup : []
, mouseover: [f3]
....
}

For each event, say, click, a function is assigned to the .onclick. This function carries out the following steps:
  1. Check if obj.eventHooks exists. If not, create one
  2. Check if obj.eventHooks.click exists. If not, create one
  3. Loop through each functions in obj.eventHooks.click
  4. For each function, attaches it to obj as a temporary obj.tmp, then executes obj.tmp(e). This makes sure that any this keyword inside that function point to the obj correctly.
A test page, using the contest template, is here. I am sure that there will be some downside along with this code, but at least at this moment it seems to solve the problems came with the winning code.

Tuesday, March 20, 2007

Javascript string replacing function

In python there's a very convinient string replacing function that comes with every string. The following example show how it works:

To construct a string:   "firstname:Runsun, lastname:Pan, project:wysiwyc"
firstname='Runsun'
lastname ='Pan'
project ='wysiwyc'
s= 'firstname:<b>%s</b>, lastname:<b>%s</b>, project:<b>%s</b>'%(firstname, lastname, project)

The symbol % attaching to the end of a string is a function to insert a series of strings (firstname, lastname, project) into the original string. This not only makes it easier to read but also easier to type, as compared to:

'firstname:<b>'+ firstname +'</b>, lastname:<b>'+ lastname+ '</b>, project:<b>'+ project + '</b>'

In javascript you don't have that luxury. I came up with a tiny function that does just that:

function ___(s)
{
var ss = arguments[0].split('___')
var out= [ss[0]]
for (var i=1;i<ss.length;i++){
out.push(arguments[i])
out.push(ss[i])
}
return out.join('')
}

So now you can do this:

s= ___('firstname:<b>___</b>, lastname:<b>___</b>, project:<b>___</b>',firstname, lastname, project)

I found that this syntax is actually better than its python cousin, because the symbol "___" implies that there's something to be filled, just like what we used to do when filling up a form with a pen.

It would look even more clear if we attach this "___()" function to the string prototype:

String.prototype._= function()
{

var ss = this.valueOf().split('___')
var out= [ss.shift()]
for (var i=0;i<ss.length;i++){
out.push(arguments[i])
out.push(ss[i])
}
return out.join('')
}

which allows this:

s= 'firstname:<b>___</b>, lastname:<b>___</b>, project:<b>___</b>'._(firstname, lastname, project)

Some other uses of this function:

Example-1:

alert('myArray=[___]'._(myArray))

Example-2:

tag = '<___ style="___">___</___>'
DIV = tag._('div','___','___','div')
SPAN = tag._('span','___','___','span')
adiv = DIV._("border:1px dashed blue; color:blue", "div example")
aspan= SPAN._("color:red;background-color:yellow", "span example")

The 2nd example gives:

div example
span example

Replace with a data in a hash


The above ___() function is already very helpful. But the original python % has one other feature:

data= {'fname':'Runsun'
,'lname':'Pan'
,'proj' :'wysiwyc'}
s= 'firstname:<b>%(fname)s</b>, lastname:<b>%(lname)s</b>, project:<b>%(proj)s</b>'%(data)

By inserting a (fname) into %s, you allow the data be in hash form. Now lets put this feature into the ___() function.

Stand-alone ___() function:

function ___(s)
{
var isObj=false
try {
isObj = arguments[1].constructor.toString().split('(')[0].split(' ')[1]=='Object'
}catch(e) {}

if (isObj)
{
var args = arguments[1]
for (var k in args) { s=s.split( '_'+k+'_').join( args[k] ) }
return s

}else{

var ss = arguments[0].split('___')
var out= [ss[0]]
for (var i=1;i<ss.length;i++){
out.push(arguments[i])
out.push(ss[i])
}
return out.join("")
}
}

Attached to string prototype:

String.prototype._= function()
{
var ss= this.valueOf()
var isObj=false
try {
isObj = arguments[0].constructor.toString().split('(')[0].split(' ')[1]=='Object'
}catch(e) {}

if (isObj)
{
var args = arguments[0]
for (var k in args) { ss=ss.split( '_'+k+'_').join( args[k] ) }
return ss

}else{

var ss = ss.split('___')
var out= [ss.shift()]
for (var i=0;i<ss.length;i++){
out.push(arguments[i])
out.push(ss[i])
}
return out.join("")
}
}

Now we can do this in javascript:

data= {fname:'Runsun'
,lname:'Pan'
,proj :'wysiwyc'}
s= 'firstname:<b>_fname_</b>, lastname:<b>_lname_</b>, project:<b>_proj_</b>'._(data)

Again, IMO, this looks better than its python cousin does.

UPDATE(7/23/07): See a regular expression version of the same function.

Saturday, March 17, 2007

Recovering CHK files

I have an old One-Touch external hard drive from Maxtor. It went crazy and generated 10,000 FILE????.CHK files about a year ago. My wife and I were worried about that the entire hard drive has gone unstable so we simply gave up using it. Recently I found some spare time trying to search for some tools to recover those CHK files.

RecognizeImageFiles.py


One of the most important file types to recover is our photos. The first step I tried was to find some python script that can recognize image files by file content but not by file extensions. There is indeed such a nice little script imghdr.py in python repository. I modified it a little to have it specifically useful in CHK image file recovery (RecognizeImageFiles).
Screenshot of RecognizeImageFiles.py execution

It was quite successful and about 500 image files were recovered. But then, what about other types of files? I went online to search for third-party tools.

UnCHK and FileCHK


Surprisingly there isn't too many tools online. The most popular tools seem to be UnCHK (by Eric Phelps) and FileCHK (by Martin Kratz). They seem to be neat and useful. However, UnCHK (version UnCHK3) froze at the very beginning:



and FileCHK gave an error that reads:

Runtime error "9":
Subscript out of range

It's possible that they couldn't recognize my One-Touch in drive F. Whatever, they don't work in my case.

MediaHeal


I then found a MediaHeal from officerecovery. The description reads:

Recovers files from corrupted hard disks. Supported are all common file systems, including NTFS, FAT12, VFAT12, FAT16, and FAT32.

I downloaded the MediaHeal for Hard Drives and gave it a try. Unfortunately, this program only aims at the entire hard drives but doesn't allow users to check folder(s):

MediaHeal doesn't allow you to choose a folder (image shrunk to fit screen)

Much worse, it froze at the very beginning on this screen:

The excution of MediaHeal demo version froze at the very beginning
(image shrunk to fit screen)


RecoverMyFiles


Finally, I found RecoverMyFiles from GetData. According to their website, this program allows users to recover deleted files even after the hard disk is reformatted (I didn't even know that it's possible):

Recover deleted files even if emptied from the Recycle Bin
Recover formatted hard drives, even if you have reinstalled Windows!
Recover your files after a hard disk crash
Get back files after a partitioning error
Recover documents, photos, video music and email.
Recover from hard drive, camera card, USB, Zip, floppy disk or other media

and it's able to recover 200 types of files. I downloaded the trial version and was amazed how efficient it was:

The screenshot of RecoverMyFile excution.

It ran smoothly and took less than 4 minutes to complete checking my 250GB One-Touch. You can check the content of each file to decide what file is valuable. Since this is a trial vresion so it doesn't allow real rescuing. But it already impressed me.

Other links


FILExt.com
http://filext.com/detaillist.php?extdetail=chk&Search=Search

Look for info about a file ext
http://shell.windows.com/fileassoc/0409/xml/redir.asp?Ext=jpg

A list of common file extensions
http://safari.oreilly.com/0596002491/winxpnut-APP-F

OfficeRecovery.com (data recovery software for corrupted files)
http://www.officerecovery.com/mediaheal/index.htm

Thursday, March 15, 2007

HTML Tablizer

Introducing a html tablizer -- an online utilite to make simple html table.

The program has an Input Section and Output Section:


Enter your table data in the Input Section and either hit [Submit] button or simply move the cursor away from the input box. Then the resulting table will be shown immediately in the Demonstration in the Output Section. Also, the corresponding HTML code will be displayed in HTML code for copy and paste.

After the HTML code and the demo result are shown, you can modify the HTML code and see the result immediately:



If the resulting table is too wide:



You can hit the button [demo on top] to bring the table up:



Enjoy tablizer here.