Jan 302008
 

On my current project, we had a requirement to pop up a message to the user when they leave our site (e.g., close the browser window). We discovered a number of sites talking about a window.close event, but it is not supported in modern browsers (IE 6, Firefox 2, Safari 2). The closest event is an unload event which gets fired when the page is unloaded.

We tried using this event in a javascript file that is included on every page:

window.onunload = popup;
 
function popup() {
  alert('I see you are leaving the site');
}

Unfortunately, an unload event is fired when the user leaves the page for any reason (such as clicking on a link). We did not want to show the popup if the user clicked on a link which stayed on the site.

Our next idea was to add an onclick to every link which would turn off the popup. Then, if the user clicks a link, nothing happens. If they leave the site another way, they get the popup.

Toby Tripp had the great idea to add these onclicks dynamically in javascript. We use prototype, so the code looks like:

staying_in_site = false;
 
$$('a').each(function(link) {
  link.observe('click', function() {staying_in_site = true;});
});
 
window.onunload = popup;
 
function popup() {
  if(staying_in_site) {
    return;
  }
  alert('I see you are leaving the site');
}

This code creates a variable which determines whether or not to show the popup. Then, we find every link with $$(‘a’). This is a CSS selector which selects all of the a elements. We iterate over these links and add a listener which sets the staying_in_site flag to true. Now, our popup code checks this flag and knows whether the user is staying on the site.

It is important to include this javascript at the bottom of the file (and not in the head). The javascript must be executed after the page is written or the links will not exist yet.

This solution is not perfect, but it accomplishes most of what we need.

Update (1/31/08): Simon Stewart suggested a cleaner method in the comments:

staying_in_site = false;
 
Event.observe(document.body, 'click', function(event) {
  if (Event.element(event).tagName == 'A') {
    staying_in_site = true;
  }
});
 
window.onunload = popup;
 
function popup() {
  if(staying_in_site) {
    return;
  }
  alert('I see you are leaving the site');
}

Instead of attaching an event listener to every link, we can attach a click listener to the whole body. Now, any click will call our function, which checks to see if you clicked on a link. Since we are not iterating over existing links, this javascript does not have to be below the links in the page.

Jan 232008
 

One of the great features of version control is that I can easily revert back to a known good state. I can do this in Subversion with the following command:

% svn revert -R .

However, if I have new files that are not in Subversion, this command will not delete them. Here is a fun ruby one liner to remove those files:

svn st | ruby -ne 'File.delete($_[1..-1].strip) if $_.match(/^\?/)'

This command loops over svn status and deletes all files from lines that start with ?.

Jan 112008
 

It seems strange, but duplicate null values do not violate unique constraints in PostgreSQL.

Inserting the same non-null value twice in a unique column fails as expected:

# create table test (
  a varchar unique
);

# insert into test values(1);
INSERT 0 1

# insert into test values(1);
ERROR:  duplicate key violates unique constraint "test_a_key"

However, the same is not true for null:

test=# insert into test values(null);
INSERT 0 1

test=# insert into test values(null);
INSERT 0 1

# select * from test;
 a
---
 1

(3 rows)

I think this is misleading, but PostgreSQL says that it is following the SQL standard: Unique Constraints.

Update (1/16/08): Pramod Sadalage showed me that Oracle actually behaves just like PostgreSQL. I’m not sure why I was seeing different behavior, but I could not reproduce the problem.

Jan 112008
 

It is possible to control the clipboard (copy and paste) from the command line in linux and OSX. In linux, the command is xsel, and in OSX, pbcopy/pbpaste.

For example, someone IMed me and asked for a subversion URL. Normally, I would type “svn info” in a terminal, use the mouse to select the URL, and press Ctrl-Insert to copy. Instead, I can just run this command:

svn info | grep URL | xsel --clipboard

Then, I can Alt-Tab back to the IM window and press Ctrl-v. There is no wasted time reaching for the mouse.

The—clipboard argument is required. Without it, xsel acts on the currently selected text in the terminal rather then the clipboard.

In OSX, the equivalent command is:

svn info | grep URL | pbcopy

pbcopy/pbpaste come with OSX. In debian flavors of linux, the following command will install xsel:

sudo apt-get install xsel

xsel can also be used to paste the clipboard. For example:

% echo ls | xsel --clipboard

% xsel --clipboard
ls

% `xsel --clipboard`
bin    dev   initrd      lost+found    mnt   root  sys  var