Javascript error: $.browser is undefined

I’ve had to fix a couple of our sites today due to the javascript error “$.browser is undefined”, If you’re using Google’s CDN to deliver your minified jQuery, you may well be seeing the same thing.

It looks like Google has updated their main 1.0 branch of jQuery to serve version 1.9 of the popular javascript library.  Unfortunately some plugins haven’t been updated (or site owners haven’t updated the plugin) to stop using $.browser which is now deprecated.

Fortunately, fixing this is just a case of hardcoding the CDN call to use version 1.8, so in this case change –

http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js

to

http://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js

And that should fix it.

So far I’ve seen problems with jQuery.autocomplete and jCrop plugins, feel free to add more in the comments.

Ajax.Autocompleter is not a constructor

Just before Xmas I spent ages struggling with the “Ajax.Autocompleter is not a constructor” error while trying to add a script.aculo.us autocompleter to a textbox.  I’ve done them loads of times before and never had an issue so unsurprisingly this infuriated me!

I checked online and found suggestions to do with referencing prototype more than once, and not including the right bits of script.aculo.us (effects.js, I think it’s in).  But none of those were the case.

In the end I found the answer myself… I’d followed the generally good practice of placing all my javascript references and code at the bottom of my page (just before /body) which is how I always do things nowadays.  This works absolutely great when working with prototype as it means the page doesn’t have to wait for the library to load and things therefore aren’t unnecessarily delayed.  Now, I say it works great for prototype, it doesn’t however work for script.aculo.us, THIS HAS TO GO IN THE HEAD!

So, there we have it, if you hit this problem and you’re doing “the right thing” by including your javascript goodies at the bottom of your page, I’m afraid that won’t work here.  Move your JS references to your head and things work dandy again.  You can still do your actual javascript code before /body (which I would suggest you do), just include the references to prototype and scriptaculous in the head.

I hope this helps…. and saves some hair pulling.

Update: 15/03/2010 – Just had another instance of this (well, a colleague did) and we’ve uncovered another area that can throw this same error! Everything looked exactly right, so we were scratching our heads for quite a while… until I looked at the HTML source and noticed a random <br/> at the top of the page. Looking at the code I noticed that my colleague had been outputting some debug type info before the start of the document (in this case the debug info was empty, but it was outputting a “br” after it. This, by the looks of it, throws out the DOM, such that Script.aculo.us can’t do it’s thing and rather usefully gives us this same standard “Ajax.Autocompeter is not a constructor” error. So, if you’re still having issues… check your source! Commenting the debug line out (and this the “br”), fixed it.

add to del.icio.us :: Bookmark Post in Technorati :: Add to Blinkslist :: add to furl :: Digg it :: add to ma.gnolia :: Stumble It! :: add to simpy :: seed the vine :: :: :: TailRank :: post to facebook :: Bookmark on Google :: Add to Netscape :: Share on Yahoo :: Add this to Live

Remove Pesonalised Search Greasemonkey Script

I just knocked up a quick Greasemonkey script to add a “Remove customisations” link next to the “View customizations” (customisations) link that appears when Google is tailoring your results based on your search history.

This is particularly useful if, like me, you want to know when this kind of thing is happening and need and quick way to remove it.  Yes, you can disable it but this gives you a more granular option.

So, here you go..

// ==UserScript==
// @name           Remove Google Customisations
// @description    Adds link to remove personal customisations from Google searches
// @include        http://www.google.co.uk/search?*q=*
// ==/UserScript==

window.addEventListener('load', function() {
	var d=document;
	var n;var as=d.getElementsByTagName('a');
	for(var i=0;i<as.length;i++){
		if(/View customi(s|z)ations/.test(as[i].textContent)){
			n=as[i];
			break;
		}
	}
	if(n){
		var a=d.createElement('a');
		a.href=d.location.href+'&pws=0';
		a.innerHTML='Remove customisations';
		n.parentNode.insertBefore(a,n.parentNode.firstChild);
	}
}, true);

That should do it.. I do have a bookmarklet version to if anyone wants it posted.

add to del.icio.us :: Bookmark Post in Technorati :: Add to Blinkslist :: add to furl :: Digg it :: add to ma.gnolia :: Stumble It! :: add to simpy :: seed the vine :: :: :: TailRank :: post to facebook :: Bookmark on Google :: Add to Netscape :: Share on Yahoo :: Add this to Live

Google Map UK Postcodes Bookmarklet

Today I found a really neat use for my Get Elements By Content function which I wrote recently.  I wanted to create a bookmarklet that allowed me to visit a page, click on the link and turn any UK postcodes in the page to a link to a Google Map.  Well, it’s pretty simple –

var pc=gbc('[a-z]{1,2}\\d{1,2}[a-z]? \\d[a-z]{2}');
for(var i=0;i<pc.length;i++){
 pc[i].innerHTML=pc[i].innerHTML.replace(/([a-z]{1,2}\d{1,2}[a-z]? \d[a-z]{2})/ig,'<a href="http://maps.google.co.uk/maps?f=q&hl=en&q=$1,UK&ie=UTF8&z=16&om=1&iwloc=addr">$1</a>');
}

Obviously you need to ‘gbc’ function from my last post, but other than that, you just need to turn it into a bookmarklet and away you go. If you have any problems, let me know.

add to del.icio.us :: Bookmark Post in Technorati :: Add to Blinkslist :: add to furl :: Digg it :: add to ma.gnolia :: Stumble It! :: add to simpy :: seed the vine :: :: :: TailRank :: post to facebook :: Bookmark on Google :: Add to Netscape :: Share on Yahoo :: Add this to Live

Javascript: GetElementsByContent

I had the inclination last week to knock up a quick Javascript function to effectively give you GetElementsByContent. So, you can call a function which returns an array of nodes which match a string (or RegExp) which you pass in, which can optionally be filtered by tag name.

Now, I make no claims that this is “a first”, as it probably isn’t, I wanted to write it, so I did.  If I’d have googled it, I’d have probably found something really quickly that did exactly what I wanted and would probably be far superior to what I have written.  I wanted to write it for fun really, but I think it’s actually quite useful, so here it is –

var gbc=function(contents,tag){
  var n=[];var s=tag||'*';
  var b=document.getElementsByTagName(s);
  var r=new RegExp(contents,'ig');
  for(var i=0;i<b.length;i++){
    for(var t=0;t<b[i].childNodes.length;t++){
      if(b[i].childNodes[t].nodeType==3&&r.test(b[i].childNodes[t].textContent)){
        n.push(b[i]);
        break;
      }
    }
  }
  return n;
}

Because I’m lazy I’ve called it ‘gbc’ (Get By Content), but obviously you can name it whatever you like.

You use it like –

var f = gbc('forums');

This would return all nodes in the current document which contain the text ‘forums’.

You could do –

var f = gbc('forums','a');

This would return all nodes matching the text ‘forums’ (within the text content, not attributes), but limit the search to just ‘a’ tags.

Because the first parameter (the text to search) is actually treated as a regex, you can actually pass it a string to treat as a regex. So –

var f = gbc('abc\\d+');

This would return all nodes which contain the text ‘abc’ followed by one or more numbers. Note the double slash, this is due to the way Javascript interprets the RegExp when using the ‘new’ style syntax, you need to escape any slashes.

That’s about it really, let me know if you use it or have any feedback.

add to del.icio.us :: Bookmark Post in Technorati :: Add to Blinkslist :: add to furl :: Digg it :: add to ma.gnolia :: Stumble It! :: add to simpy :: seed the vine :: :: :: TailRank :: post to facebook :: Bookmark on Google :: Add to Netscape :: Share on Yahoo :: Add this to Live