Clickable URLs with javascript

A client wants all email addresses and urls to be clickable in an application. I would like to develop a javascript solution for this.

I found this article that shows some example code for doing this on a particular piece of text, however, fixing the links on an entire page is a little bit more involved as it would require us to only convert the URLs that are static text – and leave the URLs, already inside an <a> tag, or appearing as tag attributes, alone.

My Solution


/**
 * A function that makes all static urls and email addresses in given DOM 
 * element's subtree to be converted to links.
 *
 * @param el DOM Element that we are checking
 *
 * This will recursively call itself until the entire subtree has been walked.
 * @author Steve Hannah .
 *
 * Some parts were adapted from http://www.arstdesign.com/articles/autolink.html
 */
function makeLinksClickable(el){

    //If no element is provided, then we will traverse the entire document.
    if ( el == null ) el = document.body;
    
    
    if ( el.nodeType == 3 /* text node */ ){
        // We only want to replace urls in text nodes
        var s = el.nodeValue;
        
        if ( s.replace(/^\s+|\s+$/g, '').length == 0) return;
            // If there is no text in this text node, we will just return and do
            // nothing.
        
        var hlink = /\b(ht|f)tp:\/\/([^ \,\;\:\!\)\(\"\'\< \>\f\n\r\t\v])+/g;
            // regex for URLs
        var mlink = /\b([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+\b/g;
            // regex for e-mail addresses
            // Copied from http://www.quirksmode.org/js/mailcheck.html
        
        var frag = document.createElement('span');
            // Because we are having difficulty putting just the A tag into
            // the document after conversion, we create a wrapper <span> tag
            // that will hold the resulting <a> tag.  Then we will 
            // insert the <span> tag into the document.

        
        // Replace URLs in this text node.
        var new_s = s.replace(hlink, 
                        function($0,$1,$2){ 
                            //s = $0.substring(1,$0.length); 
                                // remove trailing dots, if any
                            s = $0;
                            while (s.length>0 && s.charAt(s.length-1)=='.') 
                                s=s.substring(0,s.length-1);
                                // add hlink
                                                   
                            return " " + s.link(s); 
                        }
                     ) ;
                     
        // Replace Email addresses in this text node.
        new_s = new_s.replace(mlink,
                    function($0,$1,$2){ 
                            //s = $0.substring(1,$0.length); 
                                // remove trailing dots, if any
                            s = $0;
                            while (s.length>0 && s.charAt(s.length-1)=='.') 
                                s=s.substring(0,s.length-1);
                                // add hlink
                                                
                            return " " + s.link('mailto:'+s); 
                        }
                     ) ;
        
        if ( new_s != s ){
            // We only want to perform the switch if a change was made
            frag.innerHTML = new_s;
            
            var parent = el.parentNode;
            parent.replaceChild(frag, el);
            
        }
    } else {
        // This is not a text node, so we will loop through all of its child
        // nodes and recursively change the urls and email addresses in them.
        for ( var i=0, len=el.childNodes.length; i<len ; i++ ){
            if ( !el.childNodes[i] ) continue;
                // If for some reason this node is not set we skip it
            if ( el.childNodes[i].tagName == 'A' ) continue;
                // We don't want to change anything that is already inside
                // an <a> tag
            if ( el.childNodes[i].tagName == 'SCRIPT' ) continue;
                // We leave scripts alone because we don't want to screw up
                // any javascripts.
            
        
            makeLinksClickable(el.childNodes[i]);
                // Now we recursively call ourselves.
        }
    }

}


// Now we register this function to be called as soon as the document is finished
// loading.
registerOnloadHandler(makeLinksClickable);

But Safari has trouble with string.replace() callbacks:

Apparently Safari has some trouble with the string.replace() method when it comes to passing a function as the second parameter, as we have done in our solution above. See This post for information on how to beat this problem. Then we have a fully-workable, cross-browser solution for converting static URLs and email addresses to links using javascript.

Software Patents Must Stop

Here is another riduculous law-suit over a patent that should never have been granted.

It involves a company named Polaris IP suing a collection of companies (including Google and Yahoo) for using software to automatically respond to email using a sort of artificial intelligence. Polaris IP did not create the software to do this, they merely patented the idea of using computers to automatically respond to email.

Ridiculous!

American mainstream media spreading fear about Canada’s immigration policies

I was listening to the Glenn Beck show on CNN XM radio, August 21st. He and his guest (MICHAEL SCHEUER, FORMER SENIOR CIA OPERATIVE) were discussing the SPP (security and prosperity) meeting between the U.S., Canada, and Mexico. In the course of criticizing the “northern border” security, Scheuer stated that
“immigration rules are such that almost anyone who speaks French can get into [Canada]” and because of this “there is a large community of Tunisians, Moroccans and Algerians in Montreal and Quebec City, and those communities have ties into the Boston area in the United States, so it`s a dangerous situation.”, implying that Canada is a major terror threat to the United States. He underhandedly connected the security of the northern border with a possibility of “Bin Laden delivering another 20,000 to 40,000 dead Americans inside the United States”.

The transcript for this program can be found here.

The section that troubles me is:

–begin snippet —

SCHEUER: He came through Vancouver. That`s exactly right, sir. There is a large community of Tunisians, Moroccans and Algerians in Montreal and Quebec City, and those communities have ties into the Boston area in the United States, so it`s a dangerous situation.

BECK: OK. And tie in birth rates for me, Michael, because I know Canada is having not as extreme as Europe is having, but they`re having a problem with birth rates in Canada. Why is that dangerous?

SCHEUER: Well, especially in the French-speaking province of Quebec, their immigration rules are such that almost anyone who speaks French can get into the country in order to beef up the numbers of the French community, and so people from French-speaking Africa, French-speaking Asia come in very easily, but also, French-speaking North Africans from those three countries I just mentioned, Glenn.

— end snippet —

I am not an expert on Canadian immigration policy. But I have some concerns as a result of hearing this program. (Frankly, since subscribing to XM radio about a month ago I have been surprised by the ultra-protectionist opinions held by most of the mainstream media in the United States – including a veiled (and sometimes open) mistrust of Canada).

My concerns are as follows:

  1. If the claims about Quebec’s immigration policy are founded, and almost anyone who speaks French can get into the country, then this seems like an important issue that needs to be dealt with and changed.
  2. If the claims are false, then something should be done to hold people like Michael Scheuer responsible for their slanderous statements about Canada. We, as Canadians, can not afford to underestimate importance of American public opinion towards us.