log.js

Javascript weblog 2002-2004

Archived (22 October 2005)

The topics below have been archived. See newer stuff here.

Moved (1 August 2004)

Blogging has been moved to blogger.xs4all.nl/zanstra/. It's powered by blogging-engine (notably me using third party tools, I must have gotten mad), more sophisticated than my xml/xslt/batch-file/ftp-blogging engine ;-)

XmlHttpRequest in Safari 1.2 (23 May 2004)

The very handy XmlHttpRequest (Apple just released documentation) object (already available on Mozilla and IE/Win) is now also available in Safari 1.2+, so it's really an accepted and usable way to get and post your data on a web-page. WebFX might have some extra handy info on XML client-side scripting. This Google SOAP example is not really usable, because of cross-domain security.

client-side XPath (23 April 2004)

Dimitri Glazkov created a client-side javascript, so you can use XPath to query an HTML document, like this (this is native in Mozilla):

var iterator=document.evaluate("//input[@type='text']",document,null,0,null);

swapNode (8 March 2004)

The swapNode method is very handy, so I created DOM Level 2 compliant function replacement.

function DOMNode_swapNode(n1,n2)
{
  n1.parentNode.insertBefore(n2.parentNode.removeChild(n2),n1);
}

DOMNode.insertAfter (17 January 2004)

This function should have been defined in DOM Level 1, since I need it very often. Couldn't find a better place to put it, since it's not really javascript. This function insertes the DOMNode newChild after the refChild element.

function DOMNode_insertAfter(newChild,refChild)
//Post condition: if childNodes[n] is refChild, than childNodes[n+1] is newChild.
{
  var parent=refChild.parentNode;
  if(parent.lastChild==refChild) return parent.appendChild(newChild);
  else return parent.insertBefore(newChild,refChild.nextSibling);
}

View DOM source (1 January 2004)

A bookmarklet to show the HTML present in the DOM tree of your browser. Very handy if you use document.write extensive: view-DOM-source . Just try it on this page, and look for the menu of the coloured source code ;-)

How to handily use sort (7 October 2003)

I always wondered why the sort method of an Array takes a compare function as an (optional) parameter. Why wasn't this solved in the Object-Oriented fashion (whats a function doing in OO land)?

First let me show in an example how I used the sort method at first:

/***The FileList implementation*********/
function FileList()
{
  this.list=new Array();
}
FileList.prototype.add=function(o)
{
  this.list.push(o);
}
FileList.prototype.sort=function()
{
  this.list.sort(File_compare);
}

/***The File implementation*********/
function File(name,size) 
{
  this.name=name;
  this.size=size;
}
function File_compare(f1,f2)
{
  if(f1.name < f2.name) return -1;
  else if(f1.name > f2.name) return 1;
  else return 0;
}

/***Use the objects*********/
var fileList=new FileList();
fileList.add( new File('index.htm',1024) );
fileList.add( new File('default.htm',384) );
fileList.sort( FileCompare );

First I thought the usage of a function was because of the premature standardization of the language. The guys at Netscape (inventors of javascript) forgot, every object should implement a compare method (so I thought):

//This code is hypothetical, it doesn't work
File.prototype.compare=function(f1,f2)
{
  if(f1.name < f2.name) return -1;
  else if(f1.name > f2.name) return 1;
  else return 0;
}

fileList.sort();

The problem is you lose flexibility. A list of files typically needs to be sorted on multiple properties, like name and file size. Reverse order sorting is also a handy option to have. And all configurable, please.

Then I realized, I could use nested functions (a function within a function) to implement this:

FileList.prototype.sort=function(property,descending)
//--@property;type=string@Name of the property used as sort order.
//--@descending;type=boolean@Whether to sort ascending or descending
{
  function fileCompare(f1,f2)
  {
    if(f1[property] < f2[property]) return descending?-1:1;
    else if(f1[property] > f2[property]) return descending?1:-1;
    else return 0;
  }
  this.list.sort(fileCompare);
}
fileList.sort('name',true);

What's happening here? The inner function (fileCompare) has access to the local variables and arguments of the outer function (sort). With this technique, you can "configure" a function without using global variables (and thats good, because you don't want an one-sort-order-for-all).

You can't do something like this in C though. In languages like Object Pascal (Delphi), Modula-2, Perl and of course Javascript you can. Javascript (and Perl) depends on closure for this. More on closure later, because this application doesn't use the power of closure to its full extend.

"Show used scripts"-bookmarklet (6 October 2003)

Since day one of the web, I'm a view-source guy. Always wanting to know how people solved things. Nowadays, I just do view source, to check if the author implemented the thing the way I thought of it when I looked at the page. And every now and then I learn something new.

You can imagine I was shocked, when I came up with the idea of a view-included-scripts bookmarklet. Argh, it's so simple, but so very handy...

Updated:This updated script pick-your-script gives you just one prompt.

Kennify bookmarklet (8 September 2003)

From a friend I got an URL to kennify text (confused? See some South Park cartoons first). I was so impressed, so I made a bookmarklet (javascript bookmark, also called favelet), so every web-page can be kennified. So add the link to your favorites, and have fun.

Some notes. Although I rewrote the javascript of the Kenny Translator, I actually didn't change the algorithm; it's just less text. The bookmarklet doesn't work in the XML version of this log, because it Kennifies all text-nodes in the document.body tree. The bookmarklet uses this javascript resource (view-source). Thanks to q42 for the bookmarklet example. I rewrote it, because it was IE-only, and I didn't need the readyState check anyway.

Updated: Works in Mozilla. Got an Opera7-only version (works only when there's at least one script-block on the page). Safari and Opera 5 and 6 don't seem to be able to DOM-load javascript :-( Who helps me out? Updated: Marek Pawlowski mentions the "standard" kennify bookmarklet works fine from Opera version 7.5. Tested OK. Way to go Opera.

Updated: again. It works again (I forgot to change an internal IP address to one known on the internet, sorry).

Multi-line strings in javascript (14 February 2003)

Recently I found out how to use multi-line strings in javascript at GoT. Just put a backslash before the newline (like in C):

var s='This is a string\
and the string continues';

And then I wondered, why didn't I notice this before. If you can work yourself through the ECMA-262 specification (see chapter 7.3 and 7.8.4), you find that a new-line is illegal within a string. But then again, ECMA doesn't define a non-escape character after a backslash. Netscape defines, if a non-escape character is put after a backslash, you should ignore the backslash (although Netscape has deprecated this usage). Microsoft is not even mentioning what the behaviour is in these special cases.

So I ran some tests on browsers. See the results below. New-line means the escape sequence results in a newline within the string. Concat means the escape sequence is "eaten" by the browser.

Platform Browser Result
OS 9 Internet Explorer 5 concat
OS X 10.2.4 Opera 5 new-line
Safari 1.0 beta (v60) new-line
Chimera 0.6 concat
Mozilla 1.0 and 1.2.1 concat
OmniWeb 4.1 concat
iCab 2.9 concat
Internet Explorer 5.2 concat
Windows 2000 Opera 7.02 Bork new-line
Netscape 4.72 new-line
Internet Explorer 6.0 concat
Mozilla 1.3a concat

The good news is, no browser in this test chokes on this. The bad news is the behaviour is not consistent. Opera and Safari are important enough to keep consideration with (unless you're an IE weazer). It's funny, the inventors of Javascript have changed behaviour in their javascript engine.

An other bad thing: it's not documented anywhere. If you know more about this feature, please mail me about it. Hmm, I like the C# way better after all.

Regular Expressions (23 December 2002)

The global-modifier of a regular expression only works on IE/Win from version 5.5 and up. On IE/5.2 on Mac the support is also lacking.

/*This doesn't work on IE5 (it will hang, because it keeps matching 
the first match...*/
function getSites(s)
{
  var re=/(http:\/\/[^\s\"]+)/ig;
  var matches=re.exec(s);
  var result=[];
  while(matches!=null)
  {
    result[result.length]=matches[1];
    matches=re.exec(s); 
  }
  return result;
}

The problem with this: no error is generated by the javascript-parser (the global-modifier is ignored), but the behaviour is different.

Static objects (19 October 2002)

In javascript you can use static objects like the Math-object. These objects can't be instantiated themselves. Here's the trick how to do the same with our own objects.

function ClassState() 
{ 
  //Throw an error when a user tries to create this object.
  throw {number:445,description:'Object doesn\'t support this action'};
}
ClassState.global=0;
ClassState.inFunction=1;
ClassState.inEnum=2;

Hex in javascript (3 October 2002)

The use of hexadecimal values in javascript is a bit hidden. Here I'll show the main calls.

var i=0x8F8F; // hex number literal
var j=parseInt('c0c0',16); //convert hex string to a number
alert( (i+j).toString(16) ); //display the sum of i and j in hex