Archive for the ‘javascript’ Category

Developing for Opera

Thursday, July 16th, 2009

I’ve recently put a lot of time into Zemanta stuff working in Opera. There are a few things I’ve noticed that really bother me as a developer when developing for Opera.

OperaImage via Wikipedia
  1. The easiest way to be sure you’re getting a non cached file is to actually have it open in a tab and reload that tab. Emptying the cache does not seems to work as I’ve found out while caught in an alert loop.[1]

  2. I found the “don’t run scripts on this page anymore” checkbox in the alert box fascinating, but less so after I clicked it and couldn’t find a way to turn scripts back on for that specific page. Fortunately restarting the browser did the job.

  3. We load a loader.js that in turn loads other Javascript and CSS files. Unfortunately it seems I have to manually load these files in tabs in order to get them to work – even though I can see them in Dragonfly when I click them they seem to be blank. When I reload, the content appears. After that they work as expected. But even then I don’t see them loaded in the Network tab of Dragonfly.

  4. Can’t get the CSS loaded from a script to work. I don’t have any ideas, they just don’t work. I don’t see them in Dragonfly network tab (but I don’t see Javascript files either and they work).

  5. When using Dragonfly I cannot get out of the inspect DOm mode so I can’t use the site to do something while watching what is happening in the DOM – what you must do is switch to a different tab, do your stuff and then switch back.

  6. When you look at errors on a WordPress page Opera spits out loads of “-… is an unknown property” – thanks very much but properties that start with a – are supposed to be unknown to most of the browsers as they are vendor specific. This means that finding the error you’re looking for is much more difficult than it should be.

What I really hate the most when working with Opera is the lack of information about what is going on. They’ve added some really nice features in the recent releases but it is still quite far away from being a browser that people develop for. In this way it is sort of similar to IE but IE is a must and Opera isn’t…

If any of these are my mistakes I’d be glad if someone set me straight and taught me to use Opera as a developer. I bet others would too.

  1. When you have a loop that alerts something and you keep getting the alert – the only way of getting out is removing the alert from code, emptying cache and trying to hit reload between alerts. In Opera this does not seem to work as the only way to get the new file is to reload the file and you can’t do that between alerts. back
Reblog this post [with Zemanta]

Speaking about the web of data

Wednesday, February 25th, 2009

Today at 19:00 CET I’ll be speaking at a local web meet-up about the web of data. There’ll be a live feed of the talk available and since I’ll be speaking in English you can tune it. This is a quick translation of the abstract posted on Slovenian sites:

Numerous services are emerging on the web that provide data in a computer friendly form through APIs, microformats, feeds,… Even your blog is actually a database as it syndicates its content via feeds and new posts trigger a ping you can subscribe to.

This fact opens new ways of collaboration – so called mash-ups, but this isn’t really a new concept. What’s new about it is the fact that we don’t use this word anymore as all the new services are some sort of a mash-up leveraging existing services. But accessing data is not the only way to leveraging these services – it’s becoming increasingly easy to create an application that lives in other applications without their approval through browser extensions and bookmarklets.

Marko Mrdjenovič from Zemanta will talk about what you can do to make your site more mash-up friendly and why that’s becoming increasingly important. As a developer I’ll also present what options you have and give a few tips on what to do and what to avoid when developing these kind of apps.

If you have any questions during the talk use twitter to tell me and I’ll try to answer them. Or put them in the comments.

Update: The video is now online. It’s in English so go watch it and tell me what you think.

Reblog this post [with Zemanta]

Don’t make an ASS of U and ME

Friday, February 20th, 2009

What’s wrong with the following line of code (from WordPress 2.6.5, common.js)?

jQuery(function(){jQuery('#media-buttons a').tTips();});

What guarantees do you have that by the time the internal function executes the global jQuery will still be the one you expect it to be or that it will have the tTips plug-in you attached a few lines earlier? Nothing. You just ASSUME it will be. You didn’t put it there, so you can be sure that nobody will. Right.

jQuery developers knew this might be a problem so jQuery will pass a reference to the itself as an argument when triggering this event:

jQuery(function($){$('#media-buttons a').tTips();});

This would work and wouldn’t break. And it would make your platform a bit more hackable.

jQuery.readyOrDone

Thursday, February 19th, 2009

There’s a really small probability that someone might need something like this but I did and I’d like to share it.

At Zemanta we have a few different ways of loading our scripts and we cannot always control when they do. The Firefox extension will load the scripts on DOM ready, WordPress plugin will load them somewhere in the middle of the HTML, Drupal and MovableType plugins will load them in the head and IE extension will load them sometime while loading the page.

This all means that we have to delay some of our code execution to when DOM is ready and scripts are loaded. Which is where the problem kicks in.

jQuery has this nice way of doing this with $(document).ready(fn) or short $(fn) which waits until the document is ready and executes the passed fn function. If the document is ready it will execute the function immediately. Our issue lies in what “document is ready” means to jQuery – it means different thing in different browsers.

In browsers that support DOMContentLoaded (Firefox, Webkit, Opera – let’s call them modern browsers) “document is ready” means that either DOMContentLoaded event fired on the document or the load event fired on its window. On IE “document is ready” means that either onreadystatechange fired with readyState === 'complete' on the document or document.documentElement.doScroll("left") is successful (Diego Perini hack). To make this short – if you load jQuery after all the events fired in modern browsers jQuery will never know that the document is ready.

To get around this (we really don’t like having our own hacked version of jQuery) I wrote this little plugin:

(function ($) {
$.readyOrDone = function (fn) {
	var s = document.readyState;
	if (s === 'complete') {
		$.ready();
	}
	$(fn);
};
})(jQuery);

As you can see this will check if document is in a “complete” state and fire the ready method on jQuery which usually fires when DOM is ready – if it fired before it will do nothing. It will then add the function to the ready queue which also has this nice feature of firing immediately if DOM is ready.

All you have to do is change your $(fn) calls to $.readyOrDone(fn) and you have a bulletproof solution for executing functions when DOM is ready even if jQuery was late to the party and has no idea if the document is really ready.

Update: Filed a bug and hoping for the best.

Update 2: I found out that not all browsers provide the readyState property – Firefox on Ubuntu for example. Devised a new version that tries to smartly handle such cases:

(function ($) {
	var time = setTimeout(function () {}, 0),
		lastelm = null;
	$.readyOrDone = function (fn) {
		var s = document.readyState, getLast = function () {
			var elms = document.getElementsByTagName('*');
			return elms[elms.length - 1];
		};
		if (s === 'complete') {
			$.ready();
		} else if (typeof s === 'undefined') {
			lastelm = getLast();
			clearTimeout(time);
			time = setTimeout(function () {
				if (getLast() === lastelm && typeof document.readyState === 'undefined') {
					 $.ready();
				}
			}, 1000);
		}
		$(fn);
	};
})($);
Reblog this post [with Zemanta]

Getting into the graph

Sunday, January 11th, 2009

Designing forms online is a hard job. What you need to do is find the right balance between the consumer experience which is generally worse as the number of fields grows and the amount of content you or your employers want to get from the user in a single form. With this you’re defining the conversion rate of a form – less fields will, ceteris paribus, give you a higher conversion rate – which means that you should strive to have less fields in a form (although recently I saw an argument on twitter that you want for people to put some effort into forms to avoid registration from people who will never use your service1). Having many fields in a form has two major effects – users cannot easily scan the form to see if they’re actually willing to give away all the information that you want and they don’t want the form to take a lot of time. Since you sometimes can’t lower the number of required fields you can try to lesser the pain of filling them – by auto pre-filling them.

This is especially true of contact/feedback and registration forms. On contact forms the only thing consumers want to give is the message, on the other hand what you want is at least a name and a way to contact them (the others in your company might want more, but that’s a different storypost). The registration form is somewhat similar in the way that you can make it really simple by just using email and password fields but then again it’s nice if you have a way of addressing your users other than an email address and if your application is at least a bit local you also want their location.

The other side of the story is obviously that consumers don’t want to fill the same forms all the time. As time passes they’re minds are saying “Not again…” which is not that far enough from “Why can’t they get it from some place I already use”.

Into the graph

There have been a lot of attempts at solving this issue of repetitive entering of same data. There’s a way to do it with OpenID, which unfortunately isn’t ready for mass use since not many people use it. Other possibilities are public APIs of numerous services that allow you to get at least some user information if you have some data about them.

One of these APIs is Flickr‘s as it allows access to user information if you have the user’s email through flickr.people.findByEmail and then flickr.people.getInfo as is neatly demostrated by huffduffer which uses it to retrieve your Flickr avatar.

What you have now is the user’s name, “preferred” username, location and avatar (which you might have had already if the user is registered with gravatar).

The graph

Social Graph Platform Wars
Image by davemc500hats via Flickr

The other place where you can get decent information about the user is Google’s SocialGraph API. With it you get lots of services from which you can get all kinds of public information about a user. The problem with this API is that you first need a relevant entry point which must be a URL that the user owns. This can be a Flickr user URL (that you have if you successfully completed the previous step) but these don’t always produce very good results.

What seems to produce better results are twitter URLs – the only problem wasis how to get one. An easy way to get the users twitter URL is demonstrated in a blog post by Chris Heilmann. This will get you all the information you get from Flickr for all the users that are currently logged in to their twitter account. Seems that this is not possible anymore!

If you’re still not getting anything you can still ask a user for a URL – be it their blog or any social network service account. Or you can let her log in using other services that will give you a good starting point, like Facebook Connect or OpenID.

Data from the graph

What SocialGraph gives you is a list of services the user is registered with. You can also get their list of friends – if any of them are also users of your service you can suggest they also connect on your service. You might also get to know whether they use OpenID and suggest them that they use that login to log into your service too. Or you might be able to figure out what their blogs are – especially when they’re claimed on Technorati.

This information can also help you get in touch with your users as you can automatically contact them on services where you also have an account, like Facebook, twitter, friendfeed and others.

The thing is that once you have all this information you should be able to get all the public information the user has exposed on any of these services. And you can use this information to help the user by pre-filling forms or use it in other ways that a user might find helpful, but not spooky.

What you shouldn’t do is use this information in ways that might scare the user. For example if you can get the birth date from any of the services, don’t hide the fact that you did – offer a form to fill the date and prefill it. This way the user won’t be spooked if you send them a happy birthday note or you greet them with a happy birthday note.

This form should get your Twitter data and then get some of your services via Google’s SocialGraph. It’s all nicely wrapped in an hCard.

  1. Sorry I forgot your name as I’m not yet used to bookmarking twitter statuses. back
Reblog this post [with Zemanta]

Using jQuery for event handling on Objects

Sunday, January 4th, 2009

I’m working on a few projects with jQuery that need event handling. Since I like the way event handling is done in jQuery, I decided to use it to add event handling to internal objects with jQuery (1.2.6 at the time of writing). This seems very easy:

internalObject = {/* code here */};
eventHandler = $(internalObject);

This means that you could now do

eventHandler.bind('customEvent', function (ev) {
	// this is a reference to internalObject
});

and of course also

eventHandler.trigger('customEvent', {some: 'data'});

which is great.

But in a part of my code this just wouldn’t work. Unfortunately it was my first try at doing jQuery({/* custom object */}) and since I obviously wasn’t at my best when writing it I was sure this couldn’t be done. So I hacked around it.

A few weeks ago I made me a test case and figured out it works when passed an empty object ({}). So I implemented it everywhere and sure enough a part of the code stopped working. Which made me delve into the code to figure out why – a bit of debugging made me think the bug was somewhere in jQuery and I found out that there is a problem with the makeArray function. When it’s trying to create an Array it will test if the object has a length property. But as the comment in uncompressed code neatly points out //the window, strings and functions also have ‘length’ it checks a few things that allows it to handle these objects differently.

This means that

eventHandler = $({});

will work normally, while

eventHandler = $({length:0});

won’t because eventHandler length will be 0.

My problem was that the object I was passing had a length property. As such it got sucked into the else that processes arrays and other array like objects (like arguments and most probably also NodeLists). This meant that what I got back was nothing since length was initially set at 0.

Important update: Don’t do this:

eventHandler = {};
internalObject = {
	customEvent: function () {
		eventHandler.trigger('customEvent');
		/* some other handling code */
	},
	/* more code */
};
eventHandler = $(internalObject);
eventHandler.bind('customEvent', function (ev) {
	// this is a reference to internalObject
});
internalObject.customEvent();

You will inadvertently create an indefinite recursion as jQuery will try to trigger the native event and will execute elem[ type ](); where elem will be your object and type your event name. If you need an event that has the same name as a method on the object you can use triggerHandler as it will not trigger the default event.